1.6 更新日志
Furion 框架升级/发版规则升级前重点关注可能造成【破坏性】的标签类型:、、、
版本号规则:主版本号.次版本号.修订版本号
- 只要【确认】为框架
bug,则当天修复,当天发版,修订版本号加 1。 - 只要
.NET SDK版本更新,则当天升级,当天发版,修订版本号加 1。 - 如果
.csproj文件有变更,则当天发版,修订版本号加 1。 - 如果新增
拓展包,为了版本号统一,则当天发版,修订版本号加 1。 - 如果涉及到代码重构,则当天发版,次版本号
加 1,修订版本号清 0。 - 如果
.NET SDK主版本号升级,则当天发版,主版本号加 1。
如有意外不能当天发版,则会在 Issue 中说明具体发版时间,正常不会超过 3 天。
v4.8.0(未发布,全新定时任务)
新特性
突破性变化
问题修复
- 从
.NET6/7降级回.NET5找不到.AddDateOnlyConverters()和.AddTimeOnlyConverters()拓展方法问题 4.8.0 cdddf8d
- 从
文档
- 新版本定时任务文档
-
Schedular静态类文档 -
Serve.Run()入门文档文档
v4.6.9(已发布)
v4.6.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5XKW4 2022.10.25v4.6.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5X2Q0 2022.10.22v4.6.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5WQPP 2022.10.20v4.6.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5WOIV 2022.10.20v4.6.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5VPD1 2022.10.14v4.6.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5VIAQ 2022.10.13v4.6.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5V99T 2022.10.12v4.6.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5V6UE 2022.10.12v4.6.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UYQW 2022.10.11v4.6.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UQZ7 2022.10.10
新特性
-
LoggingMonitor支持FileResult类型监听 4.6.0 bf9c0b1 -
LogMessage结构UseUtcTimestamp字段,解释日志记录时间格式是UTC还是LOCAL时间 4.6.1 aab0371 - 事件总线模块重试失败后支持回调 4.6.1 #I5UVMV
-
LoggingMonitor支持序列化忽略指定属性名或属性类型 4.6.1 81c6343 -
long序列化丢精度的JsonConvert内置转换器,.AddLongTypeConverters()4.6.5 #I5VJHC aded58d -
app.EnableBuffering()拓展,解决Request.Body不能重复读问题 4.6.5 aded58d - 支持特别接口使用特定的序列化规则 4.6.6 797b0bf
-
LoggingMonitor自动解析JWT时间戳为时间格式 4.6.8 9e31b0b
-
突破性变化
- 适配
.NET 6.0.10和.NET 7 RC24.6.2 6bb2fad - 内置
Microsoft.AspNetCore.Mvc.NewtonsoftJson拓展,原因是太多人使用了 4.6.5 aded58d -
4.6.0 ec4838c"some log".SetCategory(name)拓展方法 -
4.6.5 aded58dDateOnlyJsonConverter和DateOnlyOffsetJsonConverter处理 - 事件总线触发处理程序的逻辑,由过去的
foreach改为Parallel.ForEach,吞吐量提升近 4 倍 4.6.4 7384c9c -
名称为.AddDateFormatString().AddDateTimeTypeConverters()4.6.5 aded58d - 重构日志模块设置上下文数据功能 4.6.0 1c198ee
- 适配
查看更改
由于过去版本设置日志上下文有多线程异常和堆内存溢出风险,所以重新设计了日志上下文的写法。
由:
_logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10))
.LogInformation("我是一个日志 {id}", 20);
改为:
using (var scope = _logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10)))
{
_logger.LogInformation("我是一个日志 {id}", 20);
}
// 也可以简写
using var scope = _logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10));
_logger.LogInformation("我是一个日志 {id}", 20);
-
远程请求4.6.4 7384c9c.SetTimeout和[Timeout]配置方法,采用全局统一配置
-
查看更改
默认情况下,HttpClient 请求超时时间为 100秒,可根据实际情况进行设置:
// 配置默认 HttpClient
options.AddHttpClient(string.Empty, c =>
{
c.Timeout = TimeSpan.FromMinutes(2);
});
// 配置特定客户端
options.AddHttpClient("github", c =>
{
c.Timeout = TimeSpan.FromMinutes(2);
});
问题修复
-
4.5.9+版本新增的IncludeScopes配置导致日志上下文失效 4.6.0 4a76841 - 多个
sql共用DbParameters出现冲突问题 4.6.0 #I5UO2H - 高频率写入日志导致堆内存溢出的异常问题 4.6.0 #I5UJRS
- 框架内部所有使用
.CreateLogger创建的日志对象无法应用上下文问题 4.6.0 ec4838c - 修复远程请求不能在
Worker Serivce中进行构造函数注入,原因是注册为Scope范围作用域 4.6.3 974f835 - 个别服务器的
SQL Server不支持TLS 1.2协议问题 4.6.3 974f835 -
.ToDictionary()拓展不支持JObject类型问题 4.6.5 #I5VJHC a11bf8d -
LoggingMonitor处理long类型丢精度问题 4.6.5 #I5VJHC aded58d - 动态
WebAPI在class类型上贴[ApiDescriptionSettings(false)]导致接口404问题 4.6.7 #I5WQ18 - 超高频率下发送事件总线消息,但是
GC来不及回收导致内存和CPU爆掉问题 4.6.8 dbc7935 -
JWT模块自动刷新Token达到临界值时导致自动刷新失败,并返回错误的401状态码 4.6.8 #I5WXHZ - 自动生成
vue/react/angular客户端工具库错误处理Token问题 4.6.8 #I5WXHZ - 远程请求没有正确处理
数组和集合类型的url参数 4.6.9 #I5XIQ4 - 自定义
Tenant实体且包含TenantId属性且没有继承EntityBase/Entity基类出现The entity type 'Tenant' requires a primary key to be defined4.6.9 #I4UM3E
-
其他更改
文档
- 远程请求设置客户端生命周期配置文档和新超时配置文档
-
JSON序列化处理long类型说明文档 -
JSON反序列化DateTimeOffset类型个别格式出错问题解决方案文档 -
Worker Service实现串行操作文档 - 关闭
.NET Core底层日志和远程请求日志文档 - 规范化结果支持特定接口配置独立序列化配置文档
- 日志记录文档、事件总线文档、数据库入门文档、
JSON序列化文档、远程请求文档、安全授权文档、生成前端请求代理文档
v4.5.9(已发布)
v4.5.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5ULWN 2022.10.09v4.5.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UGNS 2022.10.08v4.5.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U8Q9 2022.10.06v4.5.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U4SG 2022.10.03v4.5.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U413 2022.10.02v4.5.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U3MK 2022.10.01v4.5.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TXON 2022.09.30v4.5.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TLI6 2022.09.28v4.5.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TD4X 2022.09.27
新特性
-
.AddConsoleFormatter()拓展简化控制台日志模板配置 4.5.0 #I5TCMO - 控制台和文件日志时间默认显示
星期几4.5.1 #I5TKL5 - 控制台和文件日志支持配置
options.DateFormat日期格式化 4.5.1 #I5TKL5 - 控制台日志带颜色输出,比如高亮
日志级别4.5.1 #I5TKL5 - 控制台格式化配置
options.WriteHandler完全自定义配置 4.5.2 7fb3036 - 日志输出
JSON格式化配置 4.5.2 #I5TWC1 #I5OUT1 - 数据库日志写入独立日志模板配置、独立日期格式配置 4.5.2 #I5TWC1
-
LogMessage结构类LogDateTime,ThreadId,State属性 4.5.2 #I5TWC1 -
LoggingMonitor可配置JsonWriterOptions属性 4.5.4 #I5U375 -
Log.ScopeContext和"some log".ScopeContext拓展 4.5.4 8129693 - 新增
HttpContext.SetTokensOfResponseHeaders拓展 4.5.7 3775e65 - 新增远程请求支持
Stream文件格式上传 4.5.8 #I5UF3I - 日志模块可配置是否启用上下文功能
IncludeScopes属性 4.5.9 #I5UJRS -
LoggingMonitor日志筛选WriteFilter配置 4.5.9 6f06f12
-
突破性变化
- 😊
Furion框架文档地址为 https://furion.baiqian.ltd 4.5.4 2e3d80e -
LoggingMonitor底层逻辑,移除原来的.ScopeContext存储监听信息设计 4.5.2 #I5TWC1 -
主机未启动时构建服务的操作权限,此操作会导致内存激增,受影响方法:4.5.4 #I5U0A4 8129693App.GetOptions系列和App.GetService和Scoped.Create
- 😊
查看更改
近期发现许多开发者在主机还未启动时解析服务,这是非常不正确的行为,会导致启动时内存激增甚至溢出,常见的错误有:
- 在启动的时候通过
Scoped.Create创建作用域 - 在启动的时候通过
App.GetOptions获取选项对象 - 在启动的时候通过
App.GetService<T>解析服务
正确的做法是,启动的时候禁止使用 Scoped.Create 和 App.GetService<T>。
如需启动时获取配置应该通过:App.GetConfig<TOptions>("配置节点", true) 替代 App.GetOptions<TOptions>()。
问题修复
- 字符串日志拓展带泛型方法不能正确显示
CategoryName日志类别 4.5.0 #I5TBKL - 控制台日志设置了
.ScopeContext无效问题 4.5.2 7fb3036 -
LoggingMonitor同时配置了局部和全局日志监听触发两次问题 4.5.2 a1a97e8 -
v4.4.8+版本更新导致远程请求在个别情况下出现并发问题 4.5.2 #I5TWL3 -
LoggingMonitor配置了ReturnValueThreshold之后Json被截断引发有效性检测异常 4.5.4 #I5U375 -
LoggingMonitor不支持DataTable,DataSet,Tuple等类型问题 4.5.5 #I5U3VO - 自
v4.5.2+版本升级后出现启动时使用App.GetOptons<TOptions>异常问题 4.5.6 #I5U4OC f9a6587 -
app.UseInject(action)导致死循环 4.5.7 !608 -
LoggingMonitor报空引用异常问题 4.5.8 #I5UGCA !610 - 并发情况下设置日志上下文出现偶然性空引用问题 4.5.9 #I5UJRS
- 字符串日志拓展带泛型方法不能正确显示
其他更改
文档
- 选项监听出现触发多次的解决方案 #I5T9PR
- 日志记录文档、动态 WebAPI 文档、选项文档、
HttpContext文档、远程请求文档
本期亮点
- 支持日志配置
JSON格式化输出
- 支持日志配置
查看更改
// 控制台
services.AddConsoleFormatter(options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
// 文件
services.AddFileLogging("mytemplate.log", options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
// 数据库
services.AddDatabaseLogging<DatabaseLoggingWriter>(options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
- 支持
LoggingMonitor输出JSON格式
- 支持
查看更改
- 全局/局部启用
Json输出配置
// 全局
services.AddMonitorLogging(options =>
{
options.JsonBehavior = Furion.Logging.JsonBehavior.OnlyJson;
});
// 局部
[LoggingMonitor(JsonBehavior = Furion.Logging.JsonBehavior.OnlyJson)]
JsonBehavior只有设置为 JsonBehavior.OnlyJson 时才不会输出美观的日志。
- 写入存储介质
using Furion.Logging;
namespace Your.Core;
public class DatabaseLoggingWriter : IDatabaseLoggingWriter
{
// 支持构造函数注入任何实例,会自动释放任何服务,比如注入 IRepository,或者 SqlSugarClient
public DatabaseLoggingWriter()
{
}
public void Write(LogMessage logMsg, bool flush)
{
// 如果 JsonBehavior 配置为 OnlyJson 或者 All,那么 Context 就包含 loggingMonitor 的值
// 如果 JsonBehavior 配置为 OnlyJson,那么可直接通过 logMsg.Message 获取结果就是 json 格式
if (logMsg.LogName == "System.Logging.LoggingMonitor")
{
var jsonString = logMsg.Context.Get("loggingMonitor");
}
// 这里写你任何插入数据库的操作,无需 try catch
}
}
Json 输出格式如下:
{
"controllerName": "test-logger",
"controllerTypeName": "TestLoggerServices",
"actionName": "person",
"actionTypeName": "GetPerson",
"areaName": null,
"displayName": "Furion.Application.TestLoggerServices.GetPerson (Furion.Application)",
"localIPv4": "0.0.0.1",
"remoteIPv4": "0.0.0.1",
"httpMethod": "GET",
"requestUrl": "https://localhost:5001/api/test-logger/person/2",
"refererUrl": "https://localhost:5001/api/index.html?urls.primaryName=数据库操作演示",
"environment": "Development",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.53",
"requestHeaderAuthorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjEsIkFjY291bnQiOiJhZG1pbiIsImlhdCI6MTY2NDQ1MDUwNSwibmJmIjoxNjY0NDUwNTA1LCJleHAiOjE2NjQ0NTE3MDUsImlzcyI6ImRvdG5ldGNoaW5hIiwiYXVkIjoicG93ZXJieSBGdXJpb24ifQ.-xocNcDQGoXClceoVU5QAHIkTcOZ7ZXo0hEbzghDfFI",
"timeOperationElapsedMilliseconds": 55,
"authorizationClaims": [
{
"type": "UserId",
"valueType": "integer",
"value": "1"
},
{
"type": "Account",
"valueType": "string",
"value": "admin"
},
{
"type": "iat",
"valueType": "integer",
"value": "1664450505"
},
{
"type": "nbf",
"valueType": "integer",
"value": "1664450505"
},
{
"type": "exp",
"valueType": "integer",
"value": "1664451705"
},
{
"type": "iss",
"valueType": "string",
"value": "dotnetchina"
},
{
"type": "aud",
"valueType": "string",
"value": "powerby Furion"
}
],
"parameters": [
{
"name": "id",
"type": "System.Int32",
"value": 2
}
],
"returnInformation": {
"type": "Furion.UnifyResult.RESTfulResult`1[[System.Object, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
"actType": "Furion.Application.Persons.PersonDto",
"value": {
"StatusCode": 200,
"Data": {
"Id": 2,
"Name": null,
"Age": 0,
"Address": null,
"PhoneNumber": null,
"QQ": null,
"CreatedTime": "0001-01-01T00:00:00+00:00",
"Childrens": null,
"Posts": null
},
"Succeeded": true,
"Errors": null,
"Extras": null,
"Timestamp": 1664450517341
}
},
"exception": {
"type": "System.DivideByZeroException",
"message": "Attempted to divide by zero.",
"stackTrace": " at Furion.Application.TestLoggerServices.测试日志监听8(Int32 id) in D:\\Workplaces\\OpenSources\\Furion\\samples\\Furion.Application\\TestLoggerServices.cs:line 78\r\n at lambda_method103(Closure , Object , Object[] )\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)"
},
"validation": {
"errorCode": null,
"originErrorCode": null,
"message": "出错了啊。。。。"
}
}
- 支持远程请求上传文件
Stream流
- 支持远程请求上传文件
查看更改
- 单文件上传
- 字符串方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await "https://localhost:44316/api/test-module/upload-file"
.SetContentType("multipart/form-data")
.SetFiles(HttpFile.Create("file", fileStream, "image.png")).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 代理方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await _http.TestSingleFileProxyAsync(HttpFile.Create("file", fileStream, "image.png"));
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 多文件上传
- 字符串方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await "https://localhost:44316/api/test-module/upload-muliti-file"
.SetContentType("multipart/form-data")
.SetFiles(HttpFile.CreateMultiple("files", (fileStream, "image1.png"), (fileStream, "image2.png"))).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 代理方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await _http.TestMultiFileProxyAsync(HttpFile.CreateMultiple("files", (fileStream, "image1.png"), (fileStream, "image2.png")));
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 还支持
Bytes和Stream混合
var fileStream = new FileStream("image.png", FileMode.Open);
var bytes = File.ReadAllBytes("image.png");
var httpFile = new HttpFile
{
Name = name,
Bytes = bytes,
FileStream = fileStream,
FileName = fileName
};
var result = await "https://localhost:44316/api/test-module/upload-file"
.SetContentType("multipart/form-data")
.SetFiles(httpFile).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
LoggingMonitor全局过滤
查看更改
services.AddMonitorLogging(options =>
{
options.WriteFilter = (context) =>
{
// 获取控制器/操作描述器
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
// 你的逻辑....,不需要拦截返回 false,否则 true
return true;
};
});
v4.4.9(已发布)
v4.4.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SP37 2022.09.23v4.4.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SKUE 2022.09.22v4.4.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SEFE 2022.09.21v4.4.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5RSFD 2022.09.19v4.4.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5RHQX 2022.09.16v4.4.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5R5TI 2022.09.15v4.4.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5QVH3 2022.09.13v4.4.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5QDHX 2022.09.08v4.4.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Q3SX 2022.09.07v4.4.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PQHR 2022.09.05
新特性
- 友好异常可控制是否输出错误日志配置
LogError: true4.4.0 #I5PKJH -
DateOnlyJsonConverter和DateOnlyOffsetJsonConverter序列化转换器 !565 - 事件总线
LogEnabled配置,可控制是否输出服务日志 #I5QLY5 - 可实现任何多套规范化结果功能,支持特定控制器,特定方法 #I5QZ37
-
ILoggerFactory日志工厂动态批量添加文件日志拓展 #I5R9PO -
App.GetCommandLineConfiguration(args)解析命令行参数静态方法 803542c -
Sql代理支持返回受影响行数 #I5REJ9 - 任意自定义日志文件名支持滚动日志删除功能 #I5RFBQ
-
.pcd图片类型MIME为image/x-photo-cd支持 5fafc84 - 默认日志输出当前线程
Environment.CurrentManagedThreadIdb8fe2cd -
app.UseInject(Action<UseInjectOptions>)重载方法,简化配置 4.4.8 0b645fe
- 友好异常可控制是否输出错误日志配置
突破性变化
查看更改
public interface IHttp : IHttpDispatchProxy
{
[Post("https://www.furion.icu/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(HttpFile file);
// 支持多个文件
[Post("https://www.furion.icu/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(HttpFile[] files);
// 支持多个文件
[Post("https://www.furion.icu/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(IList<HttpFile> files);
}
// bytes 可以通过 File.ReadAllBytes(文件路径) 获取
var res = await "https://www.furion.icu/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.Create("file", bytes, "image.png")).PostAsync();
// 支持多个文件
var res = await "https://www.furion.icu/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.CreateMultiple("files", (bytes, "image1.png"), (bytes, "image2.png"))).PostAsync();
- 所有的
AddInject和UseInject参数设计 #I5QCF0
- 所有的
查看更改
public void ConfigureServices(IServiceCollection services)
{
services.AddInject(options =>
{
options.ConfigureSwaggerGen(gen =>
{
// ...
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseInject(configure: options =>
{
options.ConfigureSwagger(swg =>
{
// ...
});
options.ConfigureSwaggerUI(ui =>
{
// ...
});
});
}
- 远程请求所有
xxxAsStreamAsync返回值 #I5QVEB
- 远程请求所有
查看更改
由:
var stream = await "https://www.furion.icu/".GetAsStreamAsync();
改为:
var (stream, encoding) = await "https://www.furion.icu/".GetAsStreamAsync();
-
.Inject()支持配置更多参数,开放底层更多权限 4.4.9 1182283
-
查看更改
.Inject((builder, options) => {
options.ConfigureAppConfiguration((context, config) =>
{
});
options.ConfigureServices((context, services) =>
{
});
});
问题修复
- 远程请求代理模式非泛型参数导致数组溢出问题 #I5Q3SN
-
LoggingMonitor客户端IP记录错误 #I5QCU1 !562 - 远程请求响应报文中包含
charset=gbk进行序列化后乱码问题 #I5QVEB - 文件日志断电时丢失日志问题 db7d51b
- 动态
WebAPI或控制台贴了[ApiDescriptionSettings(Tag = "")]标签之后导致注释丢失 #I5REVF #I5RE4J - 启用数据库日志但是没有配置配置文件出现空异常问题 33817be
- 控制台日志过滤无法过滤默认主机日志问题 33817be
- 脚手架错误的日志配置问题 33817be
- 高频压测情况下写日志并设置日志上下文导致并发更新出现
System.AggregateException异常问题 #I5RFBQ - 日志文件名因
Windows和Linux路径分隔符不一致导致日志文件创建失败问题,Linux只支持/不支持\#I5RFBQ -
Oops.Oh/Bah设置.WithData之后无效问题 !580 - 基于
Redis重写事件存储器序列化IEventSource实例异常问题 4.4.7 3e45020 - 使用
Log静态类超高频率下写日志导致CPU激增问题 4.4.7 #I5SDK5 - 远程请求超高频率下发送请求导致
CPU激增问题和异常问题 4.4.8 #I5SJJR - 集成第三方配置中心时获取的不是最新数据问题 4.4.9 2cdef6b
其他更改
文档
-
.NET6升级.NET7文档 -
ASP.NET 7集成文档 - 集成第三方配置中心文档 4.4.9
- 第三方事件总线和
Furion集成文档 4.4.9 - 事件总线集成
Kafka文档 #I5P5UG - 友好异常文档、日志记录文档、远程请求文档、依赖注入文档、即时通讯文档、事件总线文档、Worker Service 文档、单元测试文档、入门指南文档、数据库新增文档
-
v4.3.9(已发布)
v4.3.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PIWD 2022.09.03v4.3.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PCXK 2022.09.02
新特性
-
AppSettings配置的ExcludeAssemblies属性,支持忽略指定程序集扫描 7b7747f -
Oops.Oh和Oops.Bah支持设置额外数据.WithData(data)#I5O38E - 定时任务
Crontab.GetSleepMilliseconds(baseTime)获取下一个发生时间的时间差 d024fae - 友好异常默认打印异常日志,避免生产环境漏掉重要异常信息 6e3a5bd
- 日志静态类
Log.CreateLoggerFactory()静态方法 75c672a - 多语言
SharedResource模式,避免硬编程 18e80c7 - 事件总线
MessageCenter静态类,解决从Fur v1.x版本升级问题 a29fc7c - 组件化
IWebComponent模式,支持.NET5+08a44c3 - 远程请求设置自己的
HttpClient功能 #I5PBR3 !545 -
LoggingMonitor支持添加更多自定义配置 #I5PEPA -
LoggingMonitor可配置WithReturnValue和ReturnValueThreshold#I5PFJ1 #I5PFOW -
LoggingMonitor可配置MethodsSettings更多信息 #I5PFJ1 #I5PFOW
-
查看更改
Serve.Run(RunOptions.Default
.AddWebComponent<XXXWebComponent>());
public class XXXWebComponent : IWebComponent
{
public void Load(WebApplicationBuilder builder, ComponentContext componentContext)
{
// ....
}
}
突破性变化
查看更改
[Interceptor(InterceptorTypes.Request)]
static void OnRequest(HttpClient client, HttpRequestMessage req)
{
}
[Interceptor(InterceptorTypes.Response)]
static void OnResponsing(HttpClien client, HttpResponseMessage res)
{
}
[Interceptor(InterceptorTypes.Exception)]
static void OnException(HttpClient client, HttpResponseMessage res, string errors)
{
}
问题修复
其他更改
文档
-
RabbitMQ事件总线文档 -
AppSettings配置文档、事件总线文档、多数据库配置文档、日志文档、定时任务文档、MessageCenter文档、远程请求文档、组件化文档、入门指南、多语言文档。
-
v4.2.13(已发布)
新特性
- 事件总线工厂,支持运行时动态添加订阅程序和移除订阅程序 #I5NNQX
- 事件总线
[EventSubscribe]事件Id支持正则表达式匹配 #I5NNQX - 事件总线
[EventSubscribe]支持局部失败重试配置 #I5NNQX -
Log全局静态类,方便随时随地记录日志 ba9b1f1 - 事件总线
options.AddSubscriber(Type)重载 42446078 -
ValidationMetadata类型FirstErrorProperty和FirstErrorMessage属性 #I5MFJT -
Serve.Run()模式WithArgs(args)方法 #I5MOJB -
[UnitOfWork]分布式事务TransactionScope支持 #I5MRTY - 16 位
MD5加密支持 #I5N8RC
突破性变化
-
Scoped.Create(async (f,s) => {})异步创建作用域方法名称为CreateAsync,避免一些情况下无法区分,同步方法不变 #I5N9XY
-
查看更改
由:
// Scoped.CreateUow 一样
await Scoped.Create(async (f, s) => {});
改为:
// Scoped.CreateUowAsync 一样
await Scoped.CreateAsync(async (f, s) => {});
-
.NET 6.0.8和.NET 7 Preview 7842d4f7
-
-
[LoggingMonitor]命名空间为System,因为使用频率越来越高 b879861
-
- 在非
Web环境中不正确使用字符串拓展方法检测机制 6389cbd
- 在非
- 所有
.Default静态属性为.Default()方法 6389cbd
- 所有
- 工作单元
IUnitOfWork所有方法参数类型,由ActionExecutingContext和ActionExecutedContext改为FilterContext#I5MHX5
- 工作单元
查看更改
public interface IUnitOfWork
{
void BeginTransaction(FilterContext context, UnitOfWorkAttribute unitOfWork);
void CommitTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork);
void RollbackTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork);
void OnCompleted(FilterContext context, FilterContext resultContext);
}
问题修复
- 日志上下文数据多次写入被清空问题以及数据库日志出现异常后停止写入 #I5LIWF
- 个别情况下跨域默认配置的响应缓存导致嵌入式资源异常问题 7a57efe
- 远程请求传入不合法的请求报文头数据触发校验失败问题 #I5LPFE
- 多线程中使用静态日志写数据库日志导致连接池耗光问题 8d5cdd6
-
EFCore 6.0之后IModelCacheKeyFactory接口方法改变导致分表分库异常问题 #I5MCZ6 EFCore#25154 EFCore!3305 -
ValidationMetadata对象Message字符串类型出现\"\"问题 #I5MFJT -
[IfException]覆盖Oops.Oh/Bah错误消息问题 4bbd854 - 数据库日志写入循环写入和频繁创建数据库连接池问题 9ce214c
-
Razor Pages不支持全局异常拦截问题 #I5MHX5 -
Razor Pages不支持全局数据验证问题 #I5MHX5 -
Razor Pages不支持工作单元[UnitOfWork]问题 #I5MHX5 -
Razor Pages不支持EFCore自动SaveChanges问题 #I5MHX5 -
Blazor Server因v4.2.2版本更新导致的问题 #I5MNFN -
[IfException]不支持多语言配置问题 #I5MPN7 - 通过
services.AddMvcFilter<LoggingMonitorAttribute>()方式注册无效问题 8d1477d - 事件总线默认
Channel管道初始化时机过晚问题,解决部分第三方依赖使用问题 #I5MM3O - 主机停止时写入日志异常问题 #I5N7S2
- 数据库上下文手动释放导致
AutoSaveChange特性出现释放异常问题 #I5NFWC -
[LoggingMonitor]循环引用序列化问题 #I5NRT9 - 远程请求传入
nullBody 参数抛出空异常问题 #I5NTUE - 事件总线默认开启模糊匹配(正则表达式)导致不必要的订阅 #I5NVOP
其他更改
文档
- 全局日志静态类
Log文档 ba9b1f1 -
Nuget本地测试包文档 - 日志文档、静态类文档、数据校验文档、Worker Service 文档、工作单元文档、依赖注入文档
- 全局日志静态类
v4.1.14(已发布)
新特性
-
Furion.Xunit拓展包,正式实现Xunit单元测试完整支持Furion063a034e -
services.AddMonitorLogging()日志监视器服务,支持非常灵活的日志操作 81df742 -
Serve.Run(silence: true)等一系列强大的静默启动功能 #I5JBSQ #I5J98T 7cced4 -
SpecificationDocumentBuilder.GetOpenApiGroups()方法获取底层的规范化接口分组信息 4ff03c5 -
logger.ScopeContext()配置日志上下文功能 #I5JC0D - 跨域配置
CorsAccessorSettings.SignalRSupport配置选项,支持配置SignalR跨域 #I5JREM - 事件总线
UseUtcTimestamp选项配置,可选择使用DateTime.UtcNow还是DateTime.Now,默认是DateTime.Now#I5JSEU - 规范化文档
[OperationId]配置,解决自定义Swagger UI不能正确显示路由问题 #I5K1IB - 远程请求
IHttpDispatchProxy方式全局拦截支持多态(继承) #I5K8FS
-
突破性变化
-
Furion.Xunit拓展包,正式实现Xunit单元测试完整支持Furion063a034e -
查看最新实现文档**Furion.Extras.DatabaseAccessor.SqlSugar拓展插件中的[SqlSugarUnitOfWork]工作单元特性,将使用通用工作单元替换** -
200848eInject.Create()方法,再也不需要了,框架提供了无敌强大的Serve.Run()静默启动方式 -
Serve.Run的ConfigureConfiguration方法参数,由configuration => {}改为(environment, configuration) => {}83c97bb
-
查看更改
// 由
Serve.Run(RunOptions.Default.ConfigureConfiguration(configuration => {
}));
// 改为:
Serve.Run(RunOptions.Default.ConfigureConfiguration((environment, configuration) => {
}));
问题修复
-
[LoggingMonitor]异常消息日志级别为Information错误问题 ab46cdf - 新版本日志组件频繁提示文件占用问题,将文件独占锁改为共享锁 #I5J3S6
- 配置数据库日志读写器为
EFCore时控制台出现无限打印问题 #I5J474 -
[LoggingMonitor]针对byte[]类型参数输出过大问题 5380f35 - 友好异常和规范化结果丢失了原始
ErrorCode问题 #I5IX2R - 新版本日志组件自定义数据库读写器注入
IRepository仓储导致死循环问题 #I5IX2R -
Mvc默认手动验证和Furion全局验证冲突问题 2a06c39 -
Serve.Run()模式不支持SuperSocket第三方包问题,原生是支持的。186ca0a -
SignalR跨域错误问题 #I5JREM -
[LoggingMonitor]将Oops.Oh和Oops.Bah记录到了错误日志中,默认应该是Information且提供可配置 #I5JZ1H - 自定义
Swagger UI之后个别UI要求必须配置operationId,否则出现guid序号 #I5K1IB - 主动抛出
NotFoundResult和NotFoundObjectResult无效问题 #I5KALZ -
[LoggingMonitor]解析方法参数但前端未传入时出现错误问题 #I5KC5P -
[LoggingMonitor]无法序列化IQueryable返回值问题 #I5KJD1 -
[LoggingMonitor]不能记录全局验证错误问题 b44087d -
[LoggingMonitor]存在注册顺序差异问题 b44087d
-
其他更改
- 底层的规范化文档
SpecificationDocumentBuilder部分方法,提供更加便捷的第三方Swagger UI集成 10f0f01
- 底层的规范化文档
文档
- 单元测试文档、入门指南文档、Worker Services 文档
本期亮点
Serve.Run()彻彻底底支持全平台,提供非常强大的静默模式
启用静默模式可以实现无阻塞方式执行程序,而且还能体验完整的 Furion 功能。
查看更改
有了 Serve.Run() 静默模式后,Furion 彻彻底底支持全平台,不管你是 控制台、Web、桌面、移动、单元测试,集成测试,基准测试等等应用程序。
Serve.Run(silence: true);
// 不会阻塞执行哦,而且从这里开始可以使用 Furion 任何功能,比如 App.Configuration....
Console.WriteLine("Hello, World!");
Console.ReadKey();
还有更多静默模式。
// RunOptions 方式
Serve.Run(RunOptions.DefaultSilence);
// LegacyRunOptions 方式
Serve.Run(LegacyRunOptions.DefaultSilence);
// GenericRunOptions 方式
Serve.Run(GenericRunOptions.DefaultSilence);
- 强大的
Furion.Xunit单元测试、集成测试
查看更改
单元测试和集成测试是保证一个系统能够持续维护和稳定运行的必备技能,但是目前现有的单元测试组件无法直接集成 Furion 的功能,最常用的就是如何在单元测试中读取配置,以及如何进行依赖注入。
在过去,Furion 只能不断的去调整,以至于适配第三方单元测试写法,搞得不伦不类!
所以,这一次不再妥协,Furion 推出自己的单元测试工具,可以让现有的单元测试如 Xunit 100% 支持 Furion 所有功能,全部保证一致的写法。
单元测试中初始化 Furion
using Furion.Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
// 配置启动类类型,第一个参数是 TestProgram 类完整限定名,第二个参数是当前项目程序集名称
[assembly: TestFramework("TestProject1.TestProgram", "TestProject1")]
namespace TestProject1;
/// <summary>
/// 单元测试启动类
/// </summary>
public class TestProgram : TestStartup
{
public TestProgram(IMessageSink messageSink) : base(messageSink)
{
// 初始化 Furion
Serve.Run(silence: true);
}
}
测试类支持完整依赖注入
using TestProject1.Services;
using Xunit;
namespace TestProject1;
public class UnitTest1
{
private readonly ICalcService _calcService;
public UnitTest1(ICalcService calcService)
{
_calcService = calcService;
}
[Fact]
public void 测试两个数的和()
{
Assert.Equal(3, _calcService.Plus(1, 2));
}
}

- 开放底层规范化文档分组接口,使得集成第三方
Swagger UI更加容易,如集成IGeekFan.AspNetCore.Knife4jUI拓展:
查看更改
只需要在 YourPoject.Web.Core 层安装 IGeekFan.AspNetCore.Knife4jUI 即可。
3.1.1 Knife4jUI 独立版本配置
var routePrefix = "api"; // 定义 swagger 路由地址,如果是跟目录,设置 string.Empty 即可
app.UseKnife4UI(options =>
{
options.RoutePrefix = routePrefix; // 配置 Knife4UI 路由地址
foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
{
options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
}
});
app.UseInject(routePrefix); // 配置 Furion 路由地址
3.1.2 Knife4jUI 和 Swagger 共存版本配置
app.UseKnife4UI(options =>
{
options.RoutePrefix = "newapi"; // 配置 Knife4UI 路由地址,现在是 /newapi
foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
{
options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
}
});
app.UseInject(); // Furion 默认 api 地址为 /api

如需实现登录之后自动将 token 添加到头部可在登录接口 AfterScript 执行以下代码:
ke.global.setAllHeader(
"Authorization",
"Bearer " + ke.response.headers["access-token"]
);

- 提供强大的日志上下文功能
// 写法一
_logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10))
.LogInformation("我是一个日志 {id}", 20);
// 写法二
_logger.ScopeContext(new Dictionary<object, object> {
{ "Name", "Furion" },
{ "UserId", 10 }
}).LogInformation("我是一个日志 {id}", 20);
// 写法三
_logger.ScopeContext(new LogContext {
// ....
}).LogInformation("我是一个日志 {id}", 20)
v4.0.0(重新起航)💖
2020 年 09 月 01 日,一个叫 Fur 的开源项目在 Gitee 的襁褓中悄然诞生,她的出生仿佛带着某种使命,没有包袱,无限可能。
她缓缓的张开双眼,干净雪亮的眼睛似乎对这个世界充满了好奇,任何事物在她眼前晃过都像是直击灵魂的思想碰撞,这些在她看来都是非常宝贵的财富。她貌似有用不完的精力,一路汲取知识,升级打怪,不断奔跑,乐此不疲。
记得 2020 年 11 月 11 日的单身节,她迎来了“一岁(v1.0.0)”生日,自那以后,IT 这个大银幕上频繁出现她的身影,越来越多 .NET5 开发者转粉,像是告诉这个世界,她就是 IT 界大明星。
每一个明星都有一个好听的艺名,她当然也不例外,2020 年 11 月 20 日,经纪人百小僧为她起名为 Furion。
2021 年 11 月 09 日起,她进入了每个孩子都经历过的叛逆期,年少轻狂喜新厌旧,抛弃了曾经支持她的 .NET5 粉丝们,投入到新的 .NET6 拥趸者怀抱中,自此过上了奢靡富足的生活。
但她过的不开心,时常在夜里想起 .NET5 的粉丝们,内心非常自责,但在双重工作压力下她毅然选择了忽视他们的诉求,仿佛他们就是累赘。
时间真的是好东西,曾经认为是对的,经过岁月的蹉跎历磨,渐渐的明白:不忘初心,方能始终。
这一次,不落下一人(.NET5,.NET6,...,.NET N),携手共进,重新起航,感恩遇见,感恩信任。
新特性
v4.0.0支持.NET5,.NET6,...,.NET N,所有的Furion项目都能够升级到该版本,重新起航,实现大统。
v3.9.2(已发布,全新日志组件)
日志模块是任何应用系统都必备的功能,可以说是最重要的模块!在 .NET 社区中有 Log4NET,NLog,Serilog 等日志组件,它们无一不是优秀的开源项目。
但由于这些日志组件历史悠久,内部兼容的 .NET 版本非常多,功能随着时间推移变得极其强大复杂,在实际项目使用中,发现每一个日志组件配置总是不那么友好,特别是在使用上不够简单。
Furion 作为全栈开发框架,在过去版本并没有提供足以满足开发者需求的日志模块,转而推荐大家集成第三方组件,如 Serilog,导致后续无法实现自定义功能和也增加了不少维护成本。
这一次,Furion 不再妥协,彻底重构了日志模块,实现日志功能/需求完全自主可控,提供给开发者几乎所有日志功能的需求!
Furion 的使用者们,是时候“更换”掉第三方日志组件,让我们一起迭代出更强更好的日志组件吧! 🍖
新特性
突破性变化
问题修复
- 修复脱敏模块模型绑定个别情况下空异常问题 #I5IM5C
文档
- 日志文档、静态类文档、数据校验文档
本期亮点
- 极易使用且强大的日志模块
查看更改
// 写入文件
services.AddFileLogging("logs/application.log");
// 写入数据库
services.AddDatabaseLogging<DatabaseLoggingWriter>();
- 强大的
[LoggingMonitor]调试日志
查看更改
using Furion.Logging;
namespace Furion.Application;
public class TestLoggerServices : IDynamicApiController
{
[LoggingMonitor]
public PersonDto GetPerson(int id)
{
return new PersonDto
{
Id = id
};
}
}
支持控制器、操作或全局注册拦截。
输出日志为:
┏━━━━━━━━━━━ Logging Monitor ━━━━━━━━━━━
┣ Furion.Application.TestLoggerServices.GetPerson (Furion.Application)
┣
┣ 控制器名称: TestLoggerServices
┣ 操作名称: GetPerson
┣ 路由信息: [area]: ; [controller]: test-logger; [action]: person
┣ 请求地址: https://localhost:44316/api/test-logger/person/11
┣ 来源地址: https://localhost:44316/api/index.html
┣ 浏览器标识: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62
┣ 客户端 IP 地址: 0.0.0.1
┣ 服务端 IP 地址: 0.0.0.1
┣ 服务端运行环境: Development
┣ 执行耗时: 31ms
┣ ━━━━━━━━━━━━━━━ 授权信息 ━━━━━━━━━━━━━━━
┣ JWT Token: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjEsIkFjY291bnQiOiJhZG1pbiIsImlhdCI6MTY1ODcxNjc5NywibmJmIjoxNjU4NzE2Nzk3LCJleHAiOjE2NTg3MTc5OTcsImlzcyI6ImRvdG5ldGNoaW5hIiwiYXVkIjoicG93ZXJieSBGdXJpb24ifQ.VYZkwwqCwlUy3aJjuL-og62I0rkxNQ96kSjEm3VgXtg
┣
┣ UserId (integer): 1
┣ Account (string): admin
┣ iat (integer): 1658716797
┣ nbf (integer): 1658716797
┣ exp (integer): 1658717997
┣ iss (string): dotnetchina
┣ aud (string): powerby Furion
┣ ━━━━━━━━━━━━━━━ 参数列表 ━━━━━━━━━━━━━━━
┣ Content-Type:
┣
┣ id (Int32): 11
┣ ━━━━━━━━━━━━━━━ 返回信息 ━━━━━━━━━━━━━━━
┣ 类型: Furion.Application.Persons.PersonDto
┣ 返回值: {"Id":11,"Name":null,"Age":0,"Address":null,"PhoneNumber":null,"QQ":null,"CreatedTime":"0001-01-01T00:00:00+00:00","Childrens":null,"Posts":null}
┗━━━━━━━━━━━ Logging Monitor ━━━━━━━━━━━
v3.8.9(已发布)
新特性
- 规范化结果
ExceptionMetadata和ValidationMetadata都可以获取ErrorCode属性 #I5GJ6D -
ValidationMetadata类StatusCode属性 #I5HB5L - 远程请求对
Url是否编码设置,[Get(WithEncodeUrl = false)]和WithEncodeUrl(false)#I5GOBC - 更强大的
JWTEncryption.SecurityReadJwtToken('token')读取解析Token静态方法 574eeb6 -
ValiationTypes.Html验证Html标签 #I5HBKC - EFCore.NamingConventions 支持,可自定义生成表名,字段名风格,比如小驼峰,蛇形命名等 #I5HBEI
-
INamedServiceProvider命名服务提供器,可解析接口多实现 #I5HF98 - 脱敏处理模块方法参数单个值处理 a22ec3c
- 脱敏词库支持
|分割词语 3106b1d
- 规范化结果
突破性变化
问题修复
-
Rider开发工具对同名脚手架 (EFCore和SqlSugar) 只显示一个问题 !518 -
UnitOfWork工作单元在EFCore中失效问题 #I5H0T3 -
JWT中Token如果存在数组类型的值时,刷新Token后丢失了历史值 #I5GXML - 远程请求
WithEncodeUrl无法在[HttpMethod]设置问题 574eeb6 -
Serve.Run()模式下添加自定义配置导致EFCore无法获取自定义配置文件问题 #I5GZ0F -
Oops.Bah进入全局异常拦截器问题 #I5H47S -
AddDbPool/AddDb扩展未根据配置Key路径读取问题 #I5H6S4 !520 -
ValiationTypes.Url正则表达式覆盖不全问题 #I5HBKC -
v3.5.x版本导致集成 EFCore.NamingConventions 失效问题 #I5HBEI -
Swagger长路由不支持问题以及[Required]配置AllowEmptyStrings无效问题 c014330 - 远程请求上传文件时请求报文
boundary和Content-Disposition设置不正确问题 #I5HEF0 - 脱敏模块替换敏感词汇出现多替换问题 a22ec3c
-
其他更改
文档
- 远程请求文档,日志记录文档、多数据库文档、PM2 部署文档、Visual Studio 高效率文档
v3.7.11(已发布)
新特性
-
Minimal API应用支持:.AddInjectMini()#I4KOQ5 - 跨域
WithExposedHeaders默认配置access-token和x-access-token42ebdfd - 脚手架默认启用
app.UseHttpLogging()HTTP日志 42ebdfd -
Furion和ASP.NET Core完整json配置的JSON Schema架构 JSON Schema -
Sql代理支持返回单个类类型参数 1d7fb5b -
Sql代理支持返回ValueTuple单个类类型参数 876a2f5 - 组件化设计模块,支持比
AppStartup更灵活便捷的设计 #components - 独立工作单元模块,支持任何第三方
ORMa02413d - 跨域
FixedClientToken配置参数 bd01638 -
throw Oops.Bah可以手动触发规范化验证失败处理 83f0036 -
FriendlyExceptionSettings的ThrowBah配置,可标记Oops.Oh不进入异常处理 76ffa7f
-
突破性变化
-
Minimal API应用支持:.AddInjectMini()#I4KOQ5 -
Furion和ASP.NET Core完整json配置的JSON Schema架构 JSON Schema - 组件化设计模块,支持比
AppStartup更灵活便捷的设计 #components - 独立工作单元单元模块,支持任何第三方
ORMa02413d -
DataValidationFilter和FriendlyExceptionFilter,解决不支持手动抛出业务异常问题 83f0036 -
.AddDb<>和.AddDbPool<>自定义委托参数签名,由Action<DbContextOptionsBuilder>改为:Action<IServiceProvider, DbContextOptionsBuilder>
-
查看更改
// 由:
options.AddDbPool<TDbContext>(DbProvider.MySql, opt => {
});
// 改为
options.AddDbPool<TDbContext>(DbProvider.MySql, (services, opt)=> {
})
问题修复
- 自
v3.6.3版本依赖,执行原生Sql添加了参数校验导致存储过程执行错误问题 #I5ERMQ -
tools/cli.ps1脚本工具出现数据库链接被占用问题 -
JWTSettings算法配置JSON Schema错误问题,感谢 @gitwentao #I5G27B !516 - 基于策略授权在不配置
Policy的情况下出现空异常问题 #I5EVF2 - 启用数据库实体跟踪时导致新增实体多次查询数据库问题 #I4J2LZ
- 不启用规范化结果导致验证失效,异常失效问题 cdb3f57
- 验证异常和友好异常冲突问题 83f0036
-
CentOS 7.9系统部署无法指定命令--urls参数问题 8cc8ee
- 自
其他更改
- 脚手架所有
.json文件,默认添加JSON Schema支持
- 脚手架所有
文档
- 组件化启动文档
-
Vue/React/Angular请求代理文档 -
JSON Schema文档,支持配置智能提示和验证 - 跨域文档、规范化文档、配置文档、日志文档、IIS 部署文档
本期亮点
- 新增
JSON Schema支持,所有.json文件支持智能提示和验证
查看更改
{
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"AllowedHosts": "*"
}

- 根据
Swagger生成Vue/React/Angular前端请求代码
Sql代理支持返回单个类类型参数
查看更改
public interface ISql : ISqlDispatchProxy
{
// 集合类型
[SqlExecute("select * from person")]
List<Person> GetPersons();
// 自 v3.7.3+ 版本支持返回单个类类型参数
[SqlExecute("select * from person where id=@id")]
Person GetPerson(int id);
}
Sql代理支持返回ValueTuple单个类类型参数
查看更改
public interface ISql : ISqlDispatchProxy
{
[SqlExecute(@"
select * from person where id =@id;
select * from person")]
(Person, List<Person>) GetData(int id); // 注意返回值是 `(Person, List<Person>)` 组合
}
- 支持
Minimal API应用
查看更改
var builder = WebApplication.CreateBuilder(args).Inject();
// 注册 Minimal 服务
builder.Services.AddInjectMini();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseInject(string.Empty);
app.MapGet("/hello", () =>
{
return "Hello, Furion";
});
app.Run();
v3.6.9(已发布,全新入口组件)
新特性
-
Serve.Run()极简主机模式,真正实现极速入门。95cac5b -
TP.Wrapper(...)拓展方法,主要用来生成规范化的日志模板 427999a - 项目类型为
<Project Sdk="Microsoft.NET.Sdk">的控制台项目 fb08a65 -
BadPageResult错误页面类型 !494 -
[SchemaId]特性,解决不同程序集相同的类名生成Swagger的SchemaId冲突问题 #I5D3CU - 远程请求
options.ApproveAllCerts()忽略所有客户端证书拓展 eb7d18a - 判断是否是单文件环境部署静态属性
App.SingleFileEnvironmentde556f0 -
WebApplicationBuilder.UseSerilogDefault()拓展 e02524c
-
突破性变化
问题修复
- 修复默认注册的
services.AddResponseCaching();服务导致.axd内嵌资源请求错误问题 !495 -
Oracle数据库执行sql必须要求命令参数和sql语言参数数量一致 #I5D057 -
IHostService类型不能自动注册问题,之前只扫描了BackgroundService派生类 968344 - 国产芯片主机不能识别
dotnet run --urls参数问题 6d4398 - 远程请求上传文件不支持特定文件后缀问题,如
.pem文件 ba42198 - 一些程序集已破坏或程序集不完整导致主机无法启动问题 d2dc3e4
- 远程请求传入
headers时类型为Dictionary<string, string>导致转换异常问题 #I5DHL9 -
Serilog单文件发布不生成日志文件 I5DQ2B
- 修复默认注册的
其他更改
文档
-
Serve.Run()文档 -
HttpContext文档 -
GlobalUsings文档 -
TP全局静态类文档 - 中间件文档、筛选器文档、审计日志文档
- 跨域文档、远程请求文档
-
精彩贡献
- !494 优秀
Pull Request辩论典范
- !494 优秀
本期亮点
- 极速入门
查看更改
Serve.Run();
[DynamicApiController]
public class HelloService
{
public string Say()
{
return "Hello, Furion";
}
}
启动浏览器查看效果,惊呆了吗!

- 内置错误页
查看更改
using Furion.FriendlyException;
public IActionResult Add(Person person)
{
if(!ModelState.IsValid)
{
return new BadPageResult();
}
}

Swagger支持Markdown
查看更改
/// <summary>
/// 测试 Markdown
/// </summary>
/// <remarks>
/// # 测试 `Markdown` 注释
///
/// 
///
/// ```cs
/// Serve.Run();
///
/// [DynamicApiController
/// public class HelloService
/// {
/// public string Say()
/// {
/// return nameof(Furion);
/// }
/// }
/// ```
///
/// 功能还不错!!!
///
/// | 商品 | 价格 | # 其他 |
/// |--------------|-----------|------------|
/// | Juicy Apples | 1.99 | *7* |
/// | Bananas | **1.89** | 5234 |
/// | Bananas | **1.89** | 5234 |
/// | Bananas | **1.89** | 5234 |
///
/// -----
///
/// # Furion 探索版
///
/// > 在过去一年,实现 `Furion` 从无到有,编写文档已逾百万字,过程心酸开源人自知。
/// >
/// > 这一路日夜兼程,嘲讽批评常伴眼耳,即便辛苦无奈、想过放弃,但为了那微不足道的存在感依然努力着。
/// >
/// > 当然,也收获了不少...越来越多拥趸者,越发精湛技术能力,更高层次思维模式,还有许多跨界跨行朋友。
/// >
/// > 在 《[开源指北] (https://gitee.com/opensource-guide/comments/)》中,我曾说道:“开源如同人的脸,好坏一面便知,缺点可能会受到嘲讽批评,优点也会收获赞扬尊重。别担心,他们正在塑造更好的你。”
/// >
/// > 所以,这一次重新起航,重塑 `Furion` 重塑自己。也许未来在某个 IT 圈但凡有人谈起 `.NET` 还能瞟到 `Furion` 的身影。
///
/// ---
///
/// 🎉 探索 Furion 未来更多可能性,实现无第三方依赖的版本,所有模块功能按需安装,按需加载。
///
/// - 作者:[百小僧] (https://gitee.com/monksoul)
/// - 日期:2021 年 08 月 30 日
///
/// ## 环境
///
/// - IDE :[Microsoft Visual Studio Enterprise 2022 Preview(64 位) 版本 17.0.0 Preview 3.1] (https://visualstudio.microsoft.com/zh-hans/vs/preview/)
/// - SDK :[.NET SDK 6] (https://dotnet.microsoft.com/download/dotnet/6.0)
/// - 语言:[C# 10](https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-10)
///
/// ## 包说明
///
/// - `Furion.Core`:无第三方依赖,可在 `.NET 6` 所有项目类型中运行。
/// - `Furion`:内部依赖 `Furion.Core` 且无第三方依赖,**聚焦 `Web` 应用**,采用共享框架 `<FrameworkReference Include="Microsoft.AspNetCore.App" />` 模式
/// </remarks>
public void MarkdownTest()
{
// ....
}

v3.5.7(已发布)
新特性
-
Options选项属性支持自定义Key名称,[MapSettings("key")]#I5B2HN -
EventBus模块事件Id支持枚举类型 2f328aa -
EventBus模块发布者PublishAsync和PublishDelayAsync重载 2f328aa -
EventBus模块拓展方法:Enum.ParseToString()和String.ParseToEnum()2f328aa -
Furion和SqlSugar脚手架 🆕🆕🆕 8d9293d -
Dapper拓展全局配置委托 #I5AYFX -
sql转实体支持多种命名策略(纯大写,纯小写,带下划线分割等等),如Oracle数据库 a90e245 -
FS.InitalContentTypeProvider()拓展方法,获取系统内所有支持的Content-Type文件提供器 6099900
-
突破性变化
- 彻底解决了
Furion不能单文件发布的问题 7e8e0b7
- 彻底解决了
问题修复
其他更改
文档
-
Furion单文件发布文档 -
Furion + SqlSugar脚手架文档 - 事件总线文档、选项文档、即时通讯文档、
.NET5升级.NET6文档、依赖注入文档、跨域文档、数据加解密文档
-
本期亮点
- 事件总线
Id支持枚举类型
查看更改
EventSubscribe("TO:DO")] // 字符串类型
public async Task EventHandler1(EventHandlerExecutingContext context)
{
// ....
}
[EventSubscribe(YourEnum.Some)] // 枚举类型
public async Task EventHandler2(EventHandlerExecutingContext context)
{
var eventEnum = context.Source.EventId.ParseToEnum(); // 将事件 Id 转换成枚举对象
// ....
}
- 事件总线发布支持更简单调用
查看更改
// 旧版本
await _eventPublisher.PublishAsync(new ChannelEventSource("ToDo:Create", name));
// 新版本
await _eventPublisher.PublishAsync("ToDo:Create", name);
await _eventPublisher.PublishAsync(YourEnum.Some); // 也支持枚举
- 选项支持属性自定义配置
Key
查看更改
"AppInfo": {
"Name": "Furion",
"Version": "1.0.0",
"Company_Name": "Baiqian" // 可以和属性不一样
}
public class AppInfoOptions : IConfigurableOptions
{
public string Name { get; set; }
public string Version { get; set; }
[MapSettings("Company_Name")] // 支持自定义
public string Company { get; set; }
}
- 日志规范化模板
查看更改
// 生成模板字符串
var template = TP.Wrapper("Furion 框架", "让 .NET 开发更简单,更通用,更流行。",
"[作者] 百小僧",
"[当前版本] v3.5.3",
"[文档地址] https://furion.icu",
"[Copyright] 百小僧, Baiqian Co.,Ltd.");
Console.WriteLine(template);
输出结果
┏━━━━━━━━━━━ Furion 框架 ━━━━━━━━━━━
┣ 让 .NET 开发更简单,更通用,更流行。
┣
┣ 作者: 百小僧
┣ 当前版本: v3.5.3
┣ 文档地址: https://furion.icu
┣ Copyright: 百小僧, Baiqian Co.,Ltd.
┗━━━━━━━━━━━ Furion 框架 ━━━━━━━━━━━
v3.4.2(已发布)
新特性
- 规范化文件
EnableAllGroups功能,可以将多个分组合并到一个分组中 9277b98 -
angular-utils客户端工具库,专门处理angular项目接口代理问题 6c70584 -
Swagger支持单个接口更多描述功能(支持html)e5e1db0 -
Swagger接口[Obsolete]过时支持功能 e5e1db0 - 动态
API的[ApiDescriptionSettings]特性 和DynamicApiControllerSettings配置 的ForceWithRoutePrefix参数,支持强制复写[Route]特性并添加DefaultRoutePrefix#I59B74
- 规范化文件
突破性变化
- 默认内置
GBK,Windows-1252,Shift-JIS,GB2312等编码支持 c456ecb -
Furion和SqlSugar脚手架
- 默认内置
问题修复
-
<inheritdoc />不能跨程序集问题 3b9d39c -
<inheritdoc />不支持带参数,不支持隐式实现接口注释问题 #I59A6W#note_10699021 -
v3.3.1版本导致Swagger不能显示问题 6763352 - 远程请求、
JSON以及Web页面不支持GBK,GB2312等国标编码问题 c456ecb - 远程请求响应报文设置了
Content-Type:charset=不能自动转换编码问题 c456ecb
-
其他更改
-
axios-utils.ts和angular-utils.ts多客户端支持
-
文档
本期亮点
- 启用
All Groups分组功能
查看更改
有时候我们为了更好的对接口进行归类,配置了 Swagger 多个分组的功能,但这样也对生成客户端请求代码造成了困扰,所以添加了新的配置:
{
"SpecificationDocumentSettings": {
"EnableAllGroups": true
}
}
- 接口过时控制
查看更改
当我们某个接口已经过时,提示尽早调用最新接口,只需要在方法上面贴 [Obsolete] 即可,如:
[Obsolete("GetName() 已经过时,请调用 GetFrameworkName() 替代")]
public string GetName()
{
return nameof(Furion);
}
[Obsolete]
public string Other()
{
// ...
}

- 单一接口更多描述
查看更改
在该版本新增了 [ApiDescriptionSettings] 的 Description 属性,支持定义更多描述,如:
[ApiDescriptionSettings(Description = "我是一段描述,显示更多内容 <button>我是按钮</button>")]
public string add()
{
//....
}

v3.3.3(已发布)
新特性
突破性变化
- 代码注释,规范化文档注释
inheritdoc语法支持 ❤️️️️ #159A6W -
.NET所有依赖包至v6.0.5版本
- 代码注释,规范化文档注释
问题修复
- 自定义全局异常
Exception后导致获取错误行号,文件空异常问题 #I53EGM - 配置数据库上下文传递空委托导致空引用异常问题 #I519AW
- 字符串模板模板
Render拓展方法返回void问题,应该返回stringGithub-#99 - 远程请求文件上传出现空情况问题(原因是缺失
Content-Type)I57ZMN
- 自定义全局异常
其他更改
文档
- 粘土对象序列化
JSON配置文档 - 前端解密
JWT文档 - 将
byte[]转url文档 - 二级虚拟目录部署文档,远程请求文档,文件上传文档,安全授权文档、规范化文档
- 粘土对象序列化
本期亮点
- ❤️️️️ 根据文件名获取
MIME或Content-Type类型
- ❤️️️️ 根据文件名获取
查看更改
var success = FS.TryGetContentType("image.png", out var contentType); // image/png
- ❤️️️️ 支持
Swagger配置登录后才能访问
{
"SpecificationDocumentSettings": {
"LoginInfo": {
"Enabled": true,
"CheckUrl": "检查登录地址",
"SubmitUrl": "提交登录地址"
}
}
}

- ❤️️️️ 支持代码注释继承,Swagger 文档注释也支持
查看更改
/// <inheritdoc cref="ITestInheritdoc" />
public class TestInheritdoc : ITestInheritdoc, IDynamicApiController
{
/// <inheritdoc cref="ITestInheritdoc.GetName"/>
public string GetName()
{
return "Furion";
}
/// <inheritdoc />
public string GetVersion()
{
return "3.3.3";
}
}
/// <summary>
/// 测试注释继承
/// </summary>
public interface ITestInheritdoc
{
/// <summary>
/// 获取名称
/// </summary>
/// <returns></returns>
string GetName();
/// <summary>
/// 获取版本
/// </summary>
/// <returns></returns>
string GetVersion();
}

v3.2.0(已发布)
新特性
突破性变化
- 所有依赖包至最新版
- 依赖注入模块核心代码,移除注册服务采用反射机制,减少反射性能损耗 acdb315
问题修复
其他更改
文档
- 定时任务文档,日志文档
- 文件上传/下载 文档,包含单文件/多文件/Base64/Byte[]
v3.1.0(已发布)
新特性
突破性变化
-
.NET6依赖包全部升级至Nuget最新版v6.0.3
-
问题修复
其他更改
- [过时] 标记
Furion.Extras.Logging.Serilog拓展包IWebHost拓展为过时状态
- [过时] 标记
文档
- 优化文档体验,新增面包屑导航,重写文档缓存,提升文档访问速度
- 更新动态 API 文档、配置文档、远程请求文档
- 更新二级虚拟目录文档
本期亮点
- 新增动态
WebApi支持小驼峰路径,如GetMyName->getMyName:
查看更改
{
"DynamicApiControllerSettings": {
"LowercaseRoute": false,
"KeepName": true,
"AsLowerCamelCase": true
}
}
- 支持
.NET6 WebApplication模式二级虚拟目录配置:
查看更改
app.UseVirtualPath(app =>
{
app.UseInject(String.Empty); // 注意 String.Empty 只是例子,可以不填或填其他的,见一分钟入门
app.MapRouteControllers();
});
v3.0.0(已发布)
Furion v3.x 版本采用 .NET6 构建。
新特性
- 远程请求支持
GET请求自动转换类类型类型对象 #I4HR5Q
- 远程请求支持
突破性变化
- 全面支持
.NET6版本
- 全面支持
问题修复
其他更改
-
d0244dToPagedList泛型约束
-
文档
- 查看 .NET6 一分钟入门
- 查看 Furion v2 升级 v3
特别鸣谢
v2.20(已发布,全新事件总线)
在 Furion v2.20+ 版本后采用 Jaina 事件总线替换原有的 EventBus
新特性
- 远程请求支持
GET请求自动转换类类型类型对象 #I4HR5Q
- 远程请求支持
突破性变化
-
EventBus模块,采用 Jaina 方式
-
问题修复
- 开启规范化结果并自定义全局异常导致异常经过
OnSucceeded过滤器 bug #I4DTVL -
.NET5.0.5+微软底层修改了[ApiController]验证失败返回IActionResult类型 #I4ISOK - 远程请求上传文件异常 0c0752
- 框架启动不支持环境变量
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES配置 !438 - 定时任务内存和 CPU 占用及特殊情况下空异常问题 12c65de
- 默认控制器启用规范化结果无效 bugc7a4a5e
- 依赖注入
InjectionAttribute特性的ExceptInterfaces单词拼写错误问题 !436 -
Sql命令参数传入Clay类型异常问题 #I4D21Q
- 开启规范化结果并自定义全局异常导致异常经过
其他更改
文档
- 事件总线新文档
v2.19(已发布)
新特性
问题修复
-
Scoped.Create在EFCore进行Add-Migration时候报空异常问题,原因是在PM环境中不存在根服务0853e74 - 定时任务执行异常后异常一直驻留内存问题,修正为执行成功自动清空过去异常 197a62b
-
Jwt拓展包不正确的代码导致 IOptions 失效#I46LUP -
Swagger枚举Schema过滤器不输出值问题 #I46LON !404 -
Swagger处理非int类型枚举转换 bug #I46QJ9 - 视图引擎编译模板生成
dll后再次加载出现IL格式化错误问题 ff52d38 - 管道
Channel读取器无法释放Handler对象问题 10f4a90 -
Worker Services下日志不输出问题 c482548 - 远程请求
multipart/form-data类型对接微信小程序上传文件 问题 d9bad03 - 工作单元上下文在某些情况下共享事务失效问题 006d439
-
Swagger枚举值在GET请求中Schema显示不正确问题 fb72fd7 - 远程请求
404不走异常过滤器问题 !426 - 自定义事件总线并发情况下调用完成后无法正确处理队列数据 !429
-
v2.19+版本之后模块化开发加载外部程序集失效问题 !433 - 定时任务 SpareTime 频繁检查导致 CPU 增高问题 aa0a2ee
-
特别鸣谢
v2.18(已发布)
新特性
突破性变化
在过去,很多开发者总是喜欢在
Startup.cs配置服务的ConfigureService方法中解析服务,这样导致内存存在溢出风险,GC 无法回收。 正确的方式是尽可能的避免ConfigureService中解析服务。如果需要在【启动时】获取配置选项,请使用App.GetConfig<TOptions>(路径, true)代替App.GetOptions<TOption>。
问题修复
文档
- 包管理工具文档
- 模板引擎、
Sql操作,数据库上下文等等文档
v2.17(已发布)
新特性
突破性变化
问题修复
其他更改
- Swagger 生成泛型 SchemaIds 默认连接符,由
Of改为_81946b6
- Swagger 生成泛型 SchemaIds 默认连接符,由
v2.16(已发布)
新特性
突破性变化
查看更改
using Furion.DataValidation;
using Furion.DependencyInjection;
using Furion.UnifyResult.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Threading.Tasks;
namespace Furion.UnifyResult
{
/// <summary>
/// RESTful 风格返回值
/// </summary>
[SuppressSniffer, UnifyModel(typeof(RESTfulResult<>))]
public class RESTfulResultProvider : IUnifyResultProvider
{
/// <summary>
/// 异常返回值
/// </summary>
/// <param name="context"></param>
/// <param name="metadata"></param>
/// <returns></returns>
public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
{
return new JsonResult(RESTfulResult(metadata.StatusCode, errors: metadata.Errors));
}
/// <summary>
/// 成功返回值
/// </summary>
/// <param name="context"></param>
/// <param name="data"></param>
/// <returns></returns>
public IActionResult OnSucceeded(ActionExecutedContext context, object data)
{
return new JsonResult(RESTfulResult(StatusCodes.Status200OK, true, data));
}
/// <summary>
/// 验证失败返回值
/// </summary>
/// <param name="context"></param>
/// <param name="metadata"></param>
/// <returns></returns>
public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
{
return new JsonResult(RESTfulResult(StatusCodes.Status400BadRequest, errors: metadata.ValidationResult));
}
/// <summary>
/// 特定状态码返回值
/// </summary>
/// <param name="context"></param>
/// <param name="statusCode"></param>
/// <param name="unifyResultSettings"></param>
/// <returns></returns>
public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
{
// 设置响应状态码
UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings);
switch (statusCode)
{
// 处理 401 状态码
case StatusCodes.Status401Unauthorized:
await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "401 Unauthorized")
, App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
break;
// 处理 403 状态码
case StatusCodes.Status403Forbidden:
await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 Forbidden")
, App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
break;
default: break;
}
}
/// <summary>
/// 返回 RESTful 风格结果集
/// </summary>
/// <param name="statusCode"></param>
/// <param name="succeeded"></param>
/// <param name="data"></param>
/// <param name="errors"></param>
/// <returns></returns>
private static RESTfulResult<object> RESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default)
{
return new RESTfulResult<object>
{
StatusCode = statusCode,
Succeeded = succeeded,
Data = data,
Errors = errors,
Extras = UnifyContext.Take(),
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
};
}
}
}
问题修复
-
MVC控制器启用规范化处理后返回new Json({})对象为null问题 #I4354S
-
其他更改
- 多语言底层设计,取消需要创建
Lang.cs空类的要求 #I434YJ -
MiniProfiler性能,减少不必要的监听
- 多语言底层设计,取消需要创建
v2.15(已发布)
新特性
问题修复
其他更改
- 系统启动性能,从 106M 减少到 84M
- 大量底层代码,包大小从 391Kb 减少到 350Kb(不带注释版本仅 64Kb)
v2.13/v2.14(已发布)
新特性
突破性变化
问题修复
其他更改
v2.10/2.11/2.12 (已发布)
该版本有多个破坏性更改,更新时请认真查看。
新特性
-
App.Configuration.Reload()拓展 #I3XYI8 -
ISubscribeHandler支持异步方法定义 #I3XYHJ -
app.UseUnifyResultStatusCodes()可配置修改返回状态码 #I3VZQH - 远程请求添加默认
User-Agent头 #I3W17C - 支持
Sql高级代理切换数据库上下文定位器 #I3XFP6 #I3XDCR - 定时任务
CronFormat自动识别 #I3Y7GT -
Sql 高级代理拦截功能 #I3YHG4 - 拦截远程请求所有异常处理 #I3YPDE
- 远程请求配置
Timeout超时时间 #I3YPPK - 新增
RSA加密算法 #I3YZNU !345 -
DataTable和DataSet支持不指定强类型返回 #I3Z6RI -
Sql字符串拓展方法设置Timeout超时时间 #I3ZKWF -
Sql高级代理[Timeout]特性,设置超时时间 #I3ZKWF
-
突破性变化
-
FakeDelete假删除/软删除所有功能 #I3XKII - 移除
PBKDF2加密算法 #I3Z0IO - 远程请求设置超时时间单位由
分钟改为秒#I3YPPK -
IJsonSerializerProvider接口参数,新增inherit参数 #I3ZQU5 -
[NonAutomatic]特性名称为[Manual]#I3XKKX -
[NotChangedListener]特性名称为[SuppressChangedListener]#I3XKLZ -
[ManualSaveChanges]名称为[ManualCommit]#I3XKNP -
DbContext.TenantIdQueryFilterExpression名称为DbContext.BuildTenantQueryFilter#I3XKTB -
[SkipScan]名称为[SuppressSniffer]#I3XN5N -
[SkipProxy]名称为[SuppressProxy]#I3XN7O -
Sql执行,性能提升 20% #I3W33U
-
问题修复
- 动态 WebAPI 扫描控制器没有屏蔽没有注册的第三方控制器 #I3Y7TJ
-
AppDbContext设置TablePrefix无效: #I3Y57Q - 修复定时任务使用异步委托导致程序终止 bug #I3XVZ0
- 事件总线一个
消息id对应多个Handler只触发第一个#I3XYP0 -
.ToPagedList()分页方法传入小于或等于 0 的页码 #I3XNAN -
JSON序列化默认DateTimeOffset异常 #I3XMOL - 继承
Serilog日志在Worker Service生成重复日志 bug #I3WA0L !331 -
粘土对象动态添加Clay类型 bug #I3W9LW -
ValidationTypes.Numeric校验数值类型正则表达式错误 #I3WADS - 数据库命令参数
DbParameter的Value是object类型的时候且不指定 #I3YKM6 -
Oracle数据库存储过程游标参数报错问题 #I3ZBYE -
Worker Services采用独立发布后无法执行问题 #I3ZH3X - 修复远程请求如果无返回值序列化异常问题 !348
其他更改
文档变化
问答答疑
-
dapper多个数据源如何继承 #I3WUOI - 关于
SpareTime多次执行问题#I3XEQU - 选项更改通知(热更新):数据库里的数据更改了如何通知选项进行改变? #I3XYI8
-
SaaS多租户添加时无法获取租户Id#I3Y5CF - 获取
_httpContextAccessor.HttpContext为空#I3Y6BI -
Ubuntu中使用App.Configuration方法读取不到值 #I3Y74H - 数据库上下文作用域问题 #I3YHXP
- 使用
UnitofWork提交事务,可以提交成功,但是系统会有错误 #I3YIWU - 数据库读写分离--非默认主库的从库随机该如何配置? #I3YVR7
-
v2.9.0 (已发布)
新特性
突破性变化
问题修复
其他更改
- 运行时内存,实现请求结束自动释放未托管资源 #I3VXAU
文档变化
-
App静态类文档、远程请求文档、分表分库文档
-
问答答疑
- 动态 WebAPI,自定义根据方法名生成 [HttpMethod] 规则报错 #I3VKQG
-
InsertAsync的时候提示ID为空 #I3VS7E -
FirstOrDefault自动过滤了TanantId字段 #I3W0VH - 对方接口返回
HttpConnectionResponseContent远程请求拿不到返回值 #I3W17C - 查询方法
FindOrDefault报错 #I3W830 -
SqlNonQuery在UnitOfWork循环执行#I3W8WW - 因
Swagger配置问题,导致Swagger中不能自动携带 token 授权的问题 #I3W934 - 远程请求
SetBody参数识别不了#I3WBM1 -
Scoped.Create里执行sql.SqlNonQuery()或者obj.insert()问题#I3WB5O - 调用函数或存储过程,怎么出参数据自定义对象?如
Oracle数据库的数组或记录 #I3W71W
v2.7.0/2.8.0 (已发布)
新特性
-
throw Oops.On("异常消息")应用多语言支持 #I3UYC2 -
Db.GetMSRepository()获取主从库仓储静态方法 #I3UBSJ - 工作单元特性,支持静态类强制性开启共享事务 #I3S9N8
-
EFCore执行sql模式打印日志 #I3SE8X - 远程请求支持默认
HttpClient配置 #I3SI17 - 新增
短 ID生成功能 #I3T7JP -
[SensitiveDetection]支持配置替换敏感词汇 #I3THIA -
SpecificationDocumentBuilder.DocumentGroups和SpecificationDocumentBuilder.CheckApiDescriptionInCurrentGroup(currentGroup, apiDescription)公开方法#I3UDSY
-
突破性变化
问题修复
-
[DataValidation]和[SensitiveDetection]多语言应用失效 #I3UH6U -
Scoped系列方法异步出现Task is cancel情况 #I3SJF6 -
Mysql数据库的ToPagedList方法返回的结果进行遍历出现MySqlConnection is aleady use问题 #I3SJQ3 -
tool/cli.psl没有包含项目名称 #I3S1T6 - 远程请求做上传文件时,没有传入
Body,程序直接跳过 #I3TKFH - 远程请求
multipart/form-data内容分割符缺失 #I3TNO9 - 远程请求代理拦截方式返回
HttpResponseMessage问题 #I3V161 -
repository.Database.SetCommandTimeout(600)无法生效#I3VAQS
-
其他更改
文档变化
问答答疑
- 默认
MasterDbContextLocator不随自定义的参数生成 #I3SDBB - 事件总线中订阅处理程序类获取不到用户信息,这个正常吗 #I3SS0U
- 在有多租户过滤器的情况下,是否有一种方式查询全量的数据 #I3T0VI
- mysql 使用
&"tools/cli.ps1"页面化加载表结构失败 #I3T4F8 - 其他 Web 层的 Startup 优先执行 #I3T8IP
- 辅助角色服务实现建议 #I3T906
- 开启
easy connection后同一内网地址浏览器可以正常访问,远程请求则无法访问#I3TA2U -
scope.ServiceProvider.GetService<IOtherService>不存在 #I3TQMV - 能否在 WPF 项目中使用呢? #I3TMCC
-
Dapper多个数据源 #I3TM9B -
L.GetSelectCulture()方法异常 #I3TQS4 - 循环中使用
IDGen.NextID()得到的结果并不是连续的 #I3UAF6 - 模块化动态加载插件支持通配符匹配.dll #I3UDT8
-
MVC模式,在Controller里快捷方式创建View页面出错 #I3UFGB - 数据库迁移没有种子数据 #I3UI7G
-
SpareTimeAttribute中 根据 Cron 表达式 自动匹配 Cron 表达式格式化方式 #I3UTKQ - 使用
workService集成SqlSugar报错 #I3V8HJ -
sqlserver 2008分页报错如何解决呢 #I3VF96
- 默认
v2.5.0/2.6.0 (已发布)
新特性
突破性变化
问题修复
- 远程调用方法错误,请求报文头
Headers不能添加到IHttpDispatchProxy的子接口上 #I3RAF7
- 远程调用方法错误,请求报文头
其他更改
- 应用启动性能,减少内存分配
文档变化
问答答疑
- 关于
Furion集群部署 #I3R3J4 - 升级最新框架以后, 数据库生成模型报错 #I3R7TP
- 数据库上下文事务执行中,
SaveNow执行后有警告 #I3RAJI -
Hangfire使用事务出现错误 #I3ROQ5 - 如何实现 cli 不执行某些表的迁移,web 请求可以正常操作呢? #I3ROU5
- 在使用定时任务时候出现的问题:继承
ISpareTimeWorker#I3RRZS -
MySql时间差 8 小时处理 #I3RSCO -
Db.GetRepository<>方法结合[UnitOfWork]后不可用 #I3RUK5 - 事务开启失败问题 #I3RYJY
- 支持
DbProvider可动态配置 #I3RYPE -
WorkService依赖注入ISingleton问题 #I3RZ1L -
ISpareTimeWorker运行期动态修改 #I3S33Q
- 关于
v2.4.0 (已发布)
新特性
突破性变化
- .NET 5 SDK 为 5.0.6 版本
-
IJsonSerializerProvider.GetSerializerOptions()接口方法 #I3QIJN
问题修复
其他更改
-
Furion框架底层性能,减少内存占用,提高应用初始化速度 92f8cc1
-
文档变化
- JSON 序列化文档、规范化结果文档、数据库上下文文档
问答答疑
-
InsertOrUpdateNowAsync报错 #I3QKO5
-
v2.3.0 (已发布)
v2.2.0 (已发布)
新特性
突破性变化
问题修复
其他更改
文档变化
- 粘土对象文档 #I3OG18
问答答疑
v2.1.0 (已发布)
新特性
突破性变化
问题修复
其他更改
- 支持应用启动的时候迁移种子数据 #I3NH3M
文档变化
问答答疑
v2.0.0 (已发布)
新特性
- 控制台应用程序及 Worker Services 支持 #I3K4DG
- 完整任务调度功能 #I3IRUX
-
Cron表达式解析 #I3IQ9Y - 支持
Swagger自定义配置swagger.json地址模板 #I3IHMX - 支持配置动态 WebApi 区域 #I3IJAZ
- 远程请求新增支持传入服务提供器
IServiceProvider#I3IVBL - 全局配置选型
SupportPackageNamePrefixs配置,支持配置包前缀 #I3K0SN - 应用启动时支持
referenceassembly类型程序集扫描 #I3K0SN - 依赖注入
AOP拦截获取方法真实特性 #I3LZBX - EFCore 手动
SaveChanges()特性 #I3N01Y - 支持
Cors跨域更多配置 #I3N2J0
突破性变化
问题修复
- 关闭
InjectMiniProfiler参数后内存缓存无效 #I3IHLR - 在多租户中调用
Tenant属性出现偶然性数据库上下文被释放的情况 #I3IC70 - Sql 代理中如果返回基元类型抛出不能将 object 转换成对应类型的异常 #I3IC84
- 存储过程多返回值的时候,outputvalues 的 name 不是定义的 MSG 的 name,是 Msg 类型。 #I3IC7Y
- PhoneNumber 手机号验证正则表达式错误 #I3ID10
- 依赖注入 AOP 拦截无法捕获内部异常 #I3IGCC
- 全局拦截标记异常已被处理后异常过滤器依然执行 #I3J463
- 自定义全局异常拦截器不起作用 #I3K1SJ
- 在 WorkerService 模式下,还是使用 WebHostEnvironment 来判断 Host 环境,会导致错误 #I3LCQY
- 定时任务
DoOnce抛空异常 bug #I3M0ZT
- 关闭
其他更改
文档变化
问答答疑
- 数据校验,自定义 ErrorMessage 无效问题 #I3ICL3
- 最新 issue 中新增的“新增常用的 JSON 序列化方法” 会导致 AOP 拦截异常 #I3I7VE
- Furion.DatabaseAccessor.PrivateEntityBase 中的 TenantId 数据类型设置为 object #I3IQV6
- 有关异常拦截和处理的疑问 #I3IUFZ
-
DataValidation在空值的情况下被忽略掉了#I3IWSM - 日志文档没有更新 #I3J1DX
- 对于 webapi 简单类型参数,是否可以以 json 方式提交 #I3J18I
-
IUnifyResultProvider实现中如果UnifyModel的 type 不是范型会报错 #I3JBXF - 如何模块化开发新功能? #I3J7ZZ
- 建议增加微服务中间件的集成 #I3JTZQ
- 二级虚拟目录部署的 swagger 的 MiniProfiler js 报错 #I3IWLR
v1.19.0 (已发布)
新特性
突破性变化
- .NET 5 SDK 至 5.0.5 版本
问题修复
其他更改
文档变化
- 数据库上下文、多租户、仓储、日志、序列化等文档。
问答答疑
v1.18.0 (已发布)
新特性
突破性变化
问题修复
其他更改
文档变化
- 数据库操作文档 #I3E84X
问答答疑
v1.17.0 (已发布)
新特性
突破性变化
-
IRepository.AsAsyncEnumerable()返回值 #I3DIQ1,调整为:rep.AsQueryable().ToListAsync()
-
问题修复
其他更改
文档变化
- 远程请求文档 #I3CPJO
问答答疑
v1.16.0 (已发布)
新特性
突破性变化
问题修复
-
MVC模式下不支持验证自定义验证逻辑 #I39LM5 - 验证数值类型正则表达式不支持负数 bug #I39YUV
- 框架启动时无法加载未被引用的程序集 bug #I3A3Z4
-
EFCoreRepository.IsAttached()方法判断错误 bug #I3A824 -
动态API驼峰显示配置无效 bug #I3AF32 -
cli.ps1不支持新版本EFCorebug #I3APO9 -
EFCore实体配置[Table]特性无效 bug #I3BAYH - 动态 WebAPI
CheckIsSplitCamelCasebug #I3BLKX - 修复动态 WebAPI 配置保留 Action 的 Async 后缀无效问题 #I3C3DA
-
JWTToken 刷新后旧的刷新 Token 依旧可用 bug #I3C8ZH - 多语言
Razor视图变量多语言乱码问题 #I3CBMU
-
其他更改
文档变化
问答答疑
-
Furion.Extras.DatabaseAccessor.SqlSugar配置多个数据库打印 SQL 语句问题 #I39PDC -
ORACLE数据库多租户模式下返回值为指定类型时系统卡死 #I39RNH - 假删除指向异常 #I39XZA
-
Furion多语言配置节是放在AppSettings里面还是外面呢? #I3A4SB - 没找到数据库上下文 #I3A5HS
- 有
QQ交流群吗? #I3AAM7 -
Vue3环境下配置SignalR跨域出错 #I3ALQ7 - 设置
Swagger参数非必填 #I3AT02 - EFCore 调用 Insert 时报
Unknown column 'Discriminator' in 'field list'异常 #I3B2LC - 逆向
mysql数据库时cli出现错误 #I3B64F - Sql 高级代理使用过程中 DateTime 类型的参数序列化失败 #I3AZXK
- 使用 Mysql 执行 Add-Migration 报错 #I3B8EW
- Saas 多租户模式-独立 Database 模式下无法获取 Tenant, 导致无法自动切换的问题#I3AVXU
- 如何自定义 WebAPI 统一结果模型 #I3BBYW #I3BBYV
- 在
Web.Entry项目新建了一个Controller,多了未知方法 #I3BKH5 -
AOP拦截如何解析服务 #I3BUM3 - 动态 WebAPI 返回参数被省略 #I3C2XR
- 如何设置某一个接口响应数据不自动转小写,按原始字段名返回 #I38L9B
- code first 如何配置自动迁移 #I3CCR0
- webapi 混合授权如何区分不同系统 #I3CJCY
- EFCore 不支持递归无限级遍历关系 #I3CET9
-
v1.15.0 (已发布)
新特性
突破性变化
问题修复
其他更改
- 代码不规范命名导致开发者阅读代码时产生歧义
文档变化
-
FluentValidation集成文档 #I38IOT
-
问答答疑
-
Furion框架版本向下兼容问题 #I38WMZ
-
v1.14.0(已发布)
新特性
突破性变化
问题修复
其他更改
文档变化
v1.13.0(已发布)
新特性
- 多语言功能及拓展 #I2DOCL
- 事件总线功能及消息中心 #I23BKN
-
Swagger分组显示隐藏配置 #I2AHH8 -
Furion.Extras.Logging.Serilog拓展插件 #I2AAN8 -
cli.ps支持-Namespace命名空间指定 #I2A175 -
Swagger规范化化文档授权失效后自动取消授权锁 #I2AIWC -
Request.Body支持重复读功能,主要解决微信 SDK 问题 #I2AMG0 - 网络请求功能及文档 #I2APGJ
-
SqlSugar拓展包支持打印sql到MiniProfiler中 #I2ASLS -
Furion.Extras.DatabaseAccesssor.Dapper拓展插件 #I2ASYA -
Furion.Extras.DatabaseAccessor.PetaPoco拓展插件 #I2AUGA - 网络请求字符串拓展方法 #I2CPQ0
-
SqlSugar拓展新增PagedList拓展 #I2CW99 - 远程请求支持参数特性验证 #I2CX5L
-
App.User获取当前授权用户信息便捷方法 #I2CZLO - 规范化文档可配置功能,支持
appsettings.json配置 #I2D1K9 - 远程请求拦截器添加方法和方法参数 #I2D2CM
- 远程请求出错返回默认值支持 #I2D44M
- 远程请求
body参数序列化支持设置PropertyNamingPolicy#I2D685 - 远程服务接口客户端配置 #I2D7PS
-
AddInject和UseInject允许自定义SecurityDefinitions和SwaggerUI#I2DIMG -
[SecurityDefine]默认构造函数 #I2DNXT -
AspectDispatchProxy动态代理类 #I2DO6I -
[QueryParameters]特性,支持一键将Action参数添加[FromQuery]特性 #I2G8TF - 动态日志配置及拓展方法 #I2GDGD
-
WebApi请求谓词默认规则配置功能 #I2M70X
突破性变化
-
.NET 5SDK 到.NET 5.0.2版本 #I2D0PZ - 框架内所有拓展类命名空间,全部迁移到
Furion.模块.Extensions下 #I2AH54 -
Swagger记住授权存储方式,替换Session存储方式为LocalStorage方式 #I2AKUA -
Furion框架包描述文件,减少框架体积 #I2APAU -
App.CanBeScanTypes为App.EffectiveTypes#I2B0ZR -
App.ServiceProvider属性并移除App.GetDuplicateXXX方法 #I2CYZE -
Db.GetDuplicateDbContext为Db.GetNewDbContext#I2CZ04 -
Db.GetSqlDispatchProxy为Db.GetSqlProxy#I2DO9T -
Aop服务拦截器,支持异步、同步两种方式 #I2B9HQ - 网络请求所有功能 #I2BMR7
-
问题修复
-
Swagger规范化化结果不一致 bug #I2ACF3 - 数据库新增或更新忽略空值操作方法报空异常 #I2AB6C
-
Startup.csAop 全局拦截无效 #I2A7T2 -
Token过期后自动刷新Token无法获取最新的用户信息 bug #I2AWQI -
[ApiDescriptionSettings(Tag="xx")]导致swagger.json报错 bug #I2B47R -
Mysqlsql 数据库查询结果tinyint类型转换出错 bug #I2BEBM - 规范化结果多次包裹类型 bug #I2BHHZ
- 动态 Api 基元类型数组问题 #I2BMS5
-
sql查询枚举类型转换异常 bug #I2BS2Y -
string.SqlQuerizeAsync<T1>()拓展返回错误 bug #I2BSTS - 动态 Api 子类重写父类方法并取别名后
Swagger异常 bug #I2C9VP - 网络请求
application/json序列化大小写问题 #I2CRJC - 多数据库定位器实体嵌套关联 bug #I2CVN0
- 跨域响应头设置无效 bug #I2CW5T
- 远程网络请求代理打印到
MiniProfilerbug #I2CZBC - 远程请求响应拦截器 bug #I2D4DG
-
SqlSugar框架AsQueryable()一直追加参数 #I2DH1D - 自动刷新
Token空异常 bug #I2DO29 - 生成
JWT Token不传过期时间出现验证 401 bug #I2DO8L -
AppStartup排序无效 #I2DVD2 - 未启用多语言服务时友好异常和验证出现空异常 #I2ECUJ
- 数据校验字母和数字组合无法匹配 bug #I2EF2Q
- 数据校验手机或固话无效 bug #I2M5IZ
-
Dapper拓展解析SqlConnection异常 bug #I2M5P2 - 开启多语言后,
EF迁移异常 bug #I2M7DT -
IEntityTypeBuilder不支持多重继承 bug #I2PAOD -
JwtHandler设置自动刷新后,匿名访问无法通过 bug #I2SDOX -
Dapper拓展中SqlServer数据库获取连接对象类型 bug #PR159
-
其他更改
文档变化
问答答疑
- 跨域设置无效 #I2ASNJ
-
MVC视图无效,原因是.cshtml文件没有设置为内容#I2AXUU -
Sql操作可以实现事务吗?#I2B0NX -
IRepository操作数据库会打开多次数据库连接 #I2BB7B - 如何进入自定义
AppAuthorizeHandler断点 #I2BGXY -
SqlSugar注入问题 #I2C2AQ - 建议增加 API 签名验证,时效验证 #I2C6ET
- 多数据库多租户同时使用
Add-Migration报错 #I2CEHS -
ISqlSugarRepository没有Getxxx方法 #I2CJLZ -
cli.ps1如何将sql里的表导出成model类 #I2CSUL - 手动修改
Swagger终结点路径无效 #I2D608 -
DefaultDbContext不能识别 #I2DCZX - 各分层项目
Startup.cs支持Configuration#I2DDUP -
Aop无法拦截,无效 #I2DEY8 -
mysql执行Add-Migration报错 #I2DSB8\ -
Entity创建时间和是否删除添加默认值 #I2E04H -
swagger中多个servers设置 #I2E0IF - 全局筛选器 没有执行 #I2E5R4
- 多数据库定位器疑问 #I2E77T
-
cli.ps逆向工程Mysql数据库报错 #I2E7I5 -
Swagger开发环境applicationsettings.json中文乱码 #I2EAG1 - 增加指定路径程序集映射 #I2EEO2
- 动态编译
cs脚本文件 #I2EH66 - 自定义中间件,返回的错误没有规范化结果 #I2NV8S
-
Swagger循环引用设置生成文档层级无效 #I2PLQQ - 配置文件支持
yaml文件吗? #I2TJ3N - 修改数据库未
mysql执行Add-Migration报错 #I2VR64 - 多数据库使用定位器时报错 #I2VR8F
-
Migration To Oracle异常 #I2WBYQ - 开发时显示
Swagger,上线时关闭Swagger,这需要怎么配置 #I2WOYV - 兼容 Mvc 复杂验证没有试验成功 #I2X3GV
-
Aop能不能支持无接口的类 #I2X8AS - 关于
JWT Token自动刷新问题 #I2YD4K - 能否增加一个拓展的
Entity,增加一些拓展的属性 #I2YDKT -
Furion无法还原包,使用Nuget下载和通过最新的的脚手架下载都提示这个问题 #I30446 - 复杂校验与特性验证不能并行 #I3046U
v1.7.0(已发布)
新特性
-
Furion.Extras.ObjectMapper.Mapster拓展包 #I29LSJ -
Furion.Extras.Logging.Serilog拓展包 #I2AAN8 -
Furion.Extras.Web.HttpContext拓展包 #I29LSM - 内置
Token刷新机制支持 #I29K57 - 动态数据库上下文,支持运行时执行
OnModelCreating#I28UDT - 支持依赖注入排除指定接口 #I29693
- 规范化结果返回时间戳字段 #I29697
- 基础
CURD父类操作例子 #I296SR -
sql.Change("定位器完整类型名称")支持 #I29LAB -
UpdateInclude和UpdateExclude忽略空参数支持 #I29VUG - 数据库上下文内置假删除查询过滤器支持 #I29Y2R
- 忽略空值排除默认时间格式 #I29VUV
-
MiniProfiler组件 #I297R9
-
突破性变化
-
AppAuthorizeHandler授权管道为异步处理 #I29MD9 -
Swagger默认启用JWT授权支持 #I29LI4 -
HttpContextUtilities名称改为HttpContextLocal#I29KQE -
UnifyResultContext名称改为UnifyContext#I29LLZ - 只有执行迁移命令才扫描种子数据 #I29E6P
- 规范化结果
Successed属性名为Succeeded#I29NMV -
Mapster对象组件,采用提供拓展方式 #I29D2M -
CacheManager拓展类 #I29LU1 -
SaveChanges拦截器 #I292LO
-
问题修复
- 未注册的数据库上下文也被引用全局查询拦截器 bug #I29ZXJ
- 手动返回
BadObjectResult或ValidationProblemDetails结果类型时规范化结果失效 bug #I29ZU9 - 动态 WebApi
KeepName,KeepVerb、SplitCamelCase无效 bug #I29X90 -
Sql代理返回元组类型出错 bug #I29SMV -
401,403状态码规范化返回值属性变大写 bug #I29M8Y -
HttpContext空异常 bug #I29LU4 - 接口无返回值没有应用规范化结果 bug #I29GT7
- 前端
Less配置文件导致主机启动失败 bug #I29E7P - 执行
sql结果转泛型后属性重复赋值 bug #I29BUO -
Swagger关闭MiniProfiler之后组中组失效 #I29789 - 未启用规范化结果时异常返回
System.Object字符 #I2969A - 正数数据验证 0 也验证通过 bug #I2955T
- 非泛型类集成泛型接口依赖注入 bug #I294YT
-
Swagger不支持new覆盖父类的 bug #I28Z1A -
JsonSerializerUtility没有公开 bug #I28WMI -
SqlSugar拓展查询泛型类型注册异常 bug #I28VMT -
Furion Tools不支持生成不同命名空间的实体 bug #I2A175 - 全局拦截器无效 bug #I2A7T2
- 新增或更新忽略空值空异常 bug #I2AB6C
其他更改
-
Token生成加密算法 #I29KIH
-
文档变化
- 日志文档 #I28Y9D
- 数据库上下文、实体拦截器、配置、一分钟入门等等文档
问答答疑
v1.4.0(已发布)
新特性
-
Furion支持二级虚拟目录部署功能 #I28B77 -
Furion.Template.RazorWithWebApi脚手架 #I28QGI -
Furion.Template.BlazorWithWebApi脚手架 #I27Z3O -
EFCore时态查询拓展 #I28AJ -
[AppDbContext(连接字符串,数据库类型)]配置支持 #I28QTB -
DateTimeOffset转DateTime拓展方法 #I27MQA -
ValidationTypes验证正则表达式智能提示 #I2801V -
ValiationTypes.WordWithNumber验证 #I2805 - 获取客户端和服务端 IP 地址 #I28QV9
-
突破性变化
问题修复
- 多数据库上下文配置定位器后实体无法正确生成 bug #I2888L
- 多租户数据库上下文实体生成 bug #I2891G
- 对象验证失败提示消息没有应用
JSON大小写配置 bug #I27UTX - 仓储
Insert或Update方法指定ignoreNullValues无效 bug #I27UN6 -
Controller派生类如果贴了[Route]特性后出现在Swagger中 bug #I27TN7 -
SqlScalar执行sql返回Nullable类型出现转换失败 bug #I27S2N -
[UnitOfWork]特性异常 bug #I27MLM -
sql静态执行方式和sql高级代理无法监听数据库连接状态 bug #I27M4F - 修复更换 Json 序列化库无效 bug,如替换为
Microsoft.AspNetCore.Mvc.NewtonsoftJson#I27M43 -
Furion Tools工具生成模型 bug #I27XI5 - 软删除没有生效 bug #I2804I
-
Furion Tools识别带多个\\的连接字符串识别 bug #I280TS,#PR91 -
Furion Tools无法取消生成 bug #I2816M -
DateTimeOffset转本地时间差 8 小时 bug #I28BA9 - 启用
bundle js&css压缩后启动异常 bug #I28KR -
ValidationTypes.Required无效 bug #PR98 - 规范化结果
OnValidateFailed参数名拼写错误 bug #PR93,#PR92 - 授权管道验证失败还显示结果 bug #PR89
其他更改
文档变化
问答答疑
v1.2.0(已发布)
新特性
- 雪花算法 #I26OXG, #PR78
-
[AppDbContext]配置数据库提供器支持 #I27G3T - 实体表数据更改监听接口
IEntityDataChangedListener#I278DD, #I278LQ - 全局服务接口 AOP 拦截功能 #I278CP
- 定位器仓储
IDbRepository<TDbContextLocator>#I276Q3 - 数据库操作
InsertOrUpdate支持排除空字符串功能 #I272OG - 数据库操作
UpdateInclude和UpdateExclude匿名对象支持 #I271X0 - 数据验证传入空对象跳过验证支持 #I273R4
- 应用启动时支持排除特定配置文件自动加载 #I26U0A
- 单个实体表名前缀支持 #I26LX0
-
MySql数据库自动配置默认版本号 #I26XQ6 - 授权处理程序代码
突破性变化
问题修复
- 视图引擎加载外部程序集出错 bug
- 依赖注入代理接口报空对象异常 bug
-
EFCore取消附加实体出错 bug - 数据库仓储在非 Web 请求下出现空异常 bug
- 多个授权策略共存问题出现无效 bug
- 友好异常
Oop.Oh不支持普通方法 bug - 获取多租户对象时数据库上下文出现作用域验证失败 bug
- 工作单元不支持
Sql代理拦截 bug #I27GST
文档变化
- 实体数据监听器 文档
- 一分钟入门、应用启动、官方脚手架、数据库操作指南、对象映射、规范化文档、异常处理、鉴权授权文档
v1.1.0(已发布)
新特性
-
Db.GetDbContext()获取默认数据库上下文方法 -
HttpContextUtility.GetCurrentHttpContext()获取全局HttpContext上下文 -
App.GetRequiredService<>解析服务方法 -
object.GetService<>对象拓展方法 - 策略授权
PolicyPipeline基类方法,支持多重判断授权 -
JWTEncryption.ValidateJwtBearerToken手动验证静态方法 - 全局数据库上下文
InsertOrUpdateIgnoreNullValues和EnabledEntityStateTracked全局配置 -
Swagger Jwt授权全局授权参数 #I26GLR -
InsertOrUpdate支持自定义判断条件功能 #I269Q1 - 字符串字段小写命名支持 #I2695D
- 字符串文本对比功能 #I268LE
- 全局异常特性消息功能 #I2662O
-
Insert或Update数据库忽略空值功能 #I264Q4
-
突破性变化
-
Fur项目名为Furion -
Db.GetRequestDbContext<>()命名为Db.GetDbContext<>() -
Db.GetDbContext<>()命名为Db.GetDuplicateDbContext<>() -
App.GetService<>解析服务的底层逻辑,大大提高了解析服务的性能 - 授权核心代码,保持和微软一致的授权规范 #I26DCB
-
App.GetRequestService<>方法 -
ValidateJwtBearerJwt 授权方法,无需手动判断了
-
问题修复
- Furion 官方脚手架生成后编译异常 bug
-
Tenant内置属性不是virtual修饰 bug -
dockerfile新命名构建失败 bug - 自定义角色授权和多个授权共存出现 403 bug #I26H1L
-
httpContext.GetEndpoint()空异常 bug #PR73 -
Oops.Oh空异常和不支持服务抛异常 bug #I26EFU,#I26GM4 -
cli.ps生成文件编码乱码 bug #I26DVT -
Swagger文件上传按钮不显示 #I26B6U - 规范化结果授权状态码序列化大小写不一致问题 #I26B26
- 未启用规范化结果时中文乱码 bug #I268T5
-
MySql异步异常捕获不到 bug #I265SO -
cli.ps1提示找不到数据库连接字符串 bug #I2647U
其他更改
- 代码性能小优化和小调整
文档变化
- 一分钟入门、安全鉴权、数据库等文档
v1.0.3(已发布)
新特性
- Mvc 模板脚手架:
Fur.Template.Mvc - WebApi 模板:
Fur.Template.Api - Mvc/WebApi 模板:
Fur.Template.App - Razar Pages 模板:
Fur.Template.Razor - Blazor 模板:
Fur.Template.Blazor
- Mvc 模板脚手架:
突破性变化
-
PagedList到System.Collections.Generic命名空间下 - 解析服务性能问题,底层代码大量优化
-
问题修复
文档变化
- 入门文档、数据库上下文文档、多数据库操作文档
v1.0.2(已发布)
新特性
突破性变化
-
Mapster包至7.0.0版 -
App.Services名为App.ServiceProvider -
App.ApplicationServices和App.GetRequestService<>() - 非 Web 主机注入拓展
-
问题修复
其他更改
-
EntityBase和Entity所有属性为vitural修饰 -
Jwt读取和解析性能 - 优化代码支持 C# 9.0 最新语法
-
MD5加密性能 #PR71 - 无用或未使用代码
-
文档
- 数据库上下文、多数据库、一分钟入门文档
v1.0.0(已发布)
新特性
- 网络请求
RemoteRequest组件 #I1YYWD -
.AddInjectBase()注入,只包含基础服务注入 - 所有服务都支持
IServiceCollection和IMvcBuilder注入 - 抛异常状态码设置功能
StatusCode -
Swagger序列化支持Pascal属性命名方式
- 网络请求
突破性变化
- 所有的包为
.NET 5正式版
- 所有的包为
问题修复
-
SqlProxy代理异步处理 bug - 数据库类型
Datetime转DateTimeOffsetbug - 属性首字母大小写序列化不匹配出现
nullbug - 对象序列化中文出现乱码 bug
- 默认序列化配置无效 bug
- 数据库非依赖注入方式提交无效 bug
- 应用程序池提交所有
DbContext空异常 bug -
Saas多租户Tenant类型字符串属性在MySql数据库下出现longtext类型 bug -
Mvc自动验证字符串空值 bug #I24M2T - 枚举注释被覆盖 bug #I24N6J
- 忽略规范化结果无效 bug #I24B8P
-
Swagger默认ContentType不是applicaiton/jsonbug #I24F3U - 内置
System.Text.Json和Newtonsoft.Json冲突 bug #I24F3U
-
其他更改
-
Fur框架域名为:https://furion.icu - 仓储
FromSqlRaw和FromSqlInterpolated接口位置 - 数据加解密性能,#PR70
-
文档
- README.md、框架介绍、数据库上下文、配置选项、多租户、跨域文档
v4.7.9(当前版本)
🚀🎉🔥 2022 年 11 月 08 日,微软发布了 .NET7 首个正式版。
Furion 第一时间完成了适配,v4 版本开始一套代码支持 .NET5-.NET7/N,支持所有 Furion 版本升级。
v4.7.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I60MFK 2022.11.11v4.7.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I60GZ8 2022.11.10v4.7.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I60591 2022.11.08v4.7.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I600R4 2022.11.08v4.7.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Z9TI 2022.11.03v4.7.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5YG48 2022.10.30v4.7.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Y6U3 2022.10.28v4.7.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Y04N 2022.10.27
新特性
- 日志模块时间格式化默认输出
毫秒部分,针对并发比较高的场景 4.7.0 c0dc36c - 写入数据库日志死循环输出检测机制 4.7.0 30dea0c
-
LoggingMonitor输出系统信息,.NET 架构和基础框架4.7.1 aeda902 - 远程请求
.SetQueries(obj, ignoreNullValue)重载方法 4.7.3 #I5Z8KC - 远程请求
.GetCookies()和.GetSetCookies()拓展方法 4.7.5 #I5ZY1L - 事件总线
.ReplaceStorerOrFallback自定义事件源存储器方法,可在自定义初始失败时回退到默认值 4.7.6 #I602NU -
LoggingMonitor输出启动信息,Cookies和请求端源信息 4.7.7 3037b04 -
JSON序列化DateOnly和TimeOnly类型转换器:.AddDateOnlyConverters()和.AddTimeOnlyConverters()4.7.9 !657 47a5fcb -
HttpContext.ReadBodyContentAsync()拓展方法重复读取Body内容 4.7.9 #I60IYU
- 日志模块时间格式化默认输出
突破性变化
- 所有脚手架支持
-f指定.NET版本 4.7.6 #I603AZ
- 所有脚手架支持
查看更改
# 创建 .NET5 版本
dotnet new furionapi -n 项目名称 -f net5
# 创建 .NET6 版本
dotnet new furionapi -n 项目名称 -f net6
# 创建 .NET7 版本
dotnet new furionapi -n 项目名称 -f net7
- 适配
.NET 6.0.11和.NET 74.7.5 7df3195
- 适配
- 所有脚手架至
.NET 74.7.5 7df3195
- 所有脚手架至
-
LogContext类型的所有方法至Furion.Logging命名空间下,解决空异常问题 4.7.3 #I5YOT3
-
查看更改
由:
var value = logContext.Get("Key"); // 过去如果 logContext == null 报错
改为:
using Furion.Logging;
var value = logContext.Get("Key"); // 新版本不会报错,且 value = null
- 旧版本定时任务为
弃用状态(一周内发布新版),如需取消警告在.csproj中添加<NoWarn>0618</NoWarn>4.7.9 0ff3ac0
- 旧版本定时任务为
问题修复
- 生成
JWT Token时间戳和自动刷新逻辑在高并发下检查有效性不够精确问题,原因是时间戳丢掉了毫秒部分 4.7.0 3c0c017 - 在
IDatabaseLoggingWriter实现类中输出日志导致死循环问题 4.7.0 30dea0c - 规范化结果
OnResponseStatusCodes方法在Response已完成写入时设置出现异常问题 4.7.2 #I5YBHL -
L.SetCulture("zh-CN");在Response已完成写入时设置出现异常问题 4.7.2 #I5YBHL - 动态
WebAPI在类上配置[Route]特性且包含[action]模板导致生成错误接口路径 4.7.2 #I5YEZQ - 启用二级虚拟目录
AppSettings:VirtualPath导致swagger的miniprofile加载失败 4.7.3 #I5Z8RM -
LoggingMonitor监听带有[FromServices]的方法参数或接口类型参数出错 4.7.7 3037b04 -
HttpRequest通过.ReadBodyContentAsync()读取不到Body问题 4.7.9 #I60IYU
- 生成
其他更改
文档
-
IIS回收问题解决方案文档 - 远程请求获取
Cookies文档 -
LoggingMonitor写入数据库文档 - JSON 序列化
DateOnly和TimeOnly类型处理文档 -
HttpContext读取Body内容文档 -
PM2配置文件json部署文档 - 日志记录文档、定时任务文档、远程请求文档、脚手架文档
-
特别贡献
v4.6.9(已发布)
v4.6.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5XKW4 2022.10.25v4.6.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5X2Q0 2022.10.22v4.6.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5WQPP 2022.10.20v4.6.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5WOIV 2022.10.20v4.6.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5VPD1 2022.10.14v4.6.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5VIAQ 2022.10.13v4.6.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5V99T 2022.10.12v4.6.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5V6UE 2022.10.12v4.6.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UYQW 2022.10.11v4.6.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UQZ7 2022.10.10
新特性
-
LoggingMonitor支持FileResult类型监听 4.6.0 bf9c0b1 -
LogMessage结构UseUtcTimestamp字段,解释日志记录时间格式是UTC还是LOCAL时间 4.6.1 aab0371 - 事件总线模块重试失败后支持回调 4.6.1 #I5UVMV
-
LoggingMonitor支持序列化忽略指定属性名或属性类型 4.6.1 81c6343 -
long序列化丢精度的JsonConvert内置转换器,.AddLongTypeConverters()4.6.5 #I5VJHC aded58d -
app.EnableBuffering()拓展,解决Request.Body不能重复读问题 4.6.5 aded58d - 支持特别接口使用特定的序列化规则 4.6.6 797b0bf
-
LoggingMonitor自动解析JWT时间戳为时间格式 4.6.8 9e31b0b
-
突破性变化
- 适配
.NET 6.0.10和.NET 7 RC24.6.2 6bb2fad - 内置
Microsoft.AspNetCore.Mvc.NewtonsoftJson拓展,原因是太多人使用了 4.6.5 aded58d -
4.6.0 ec4838c"some log".SetCategory(name)拓展方法 -
4.6.5 aded58dDateOnlyJsonConverter和DateOnlyOffsetJsonConverter处理 - 事件总线触发处理程序的逻辑,由过去的
foreach改为Parallel.ForEach,吞吐量提升近 4 倍 4.6.4 7384c9c -
名称为.AddDateFormatString().AddDateTimeTypeConverters()4.6.5 aded58d - 重构日志模块设置上下文数据功能 4.6.0 1c198ee
- 适配
查看更改
由于过去版本设置日志上下文有多线程异常和堆内存溢出风险,所以重新设计了日志上下文的写法。
由:
_logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10))
.LogInformation("我是一个日志 {id}", 20);
改为:
using (var scope = _logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10)))
{
_logger.LogInformation("我是一个日志 {id}", 20);
}
// 也可以简写
using var scope = _logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10));
_logger.LogInformation("我是一个日志 {id}", 20);
-
远程请求4.6.4 7384c9c.SetTimeout和[Timeout]配置方法,采用全局统一配置
-
查看更改
默认情况下,HttpClient 请求超时时间为 100秒,可根据实际情况进行设置:
// 配置默认 HttpClient
options.AddHttpClient(string.Empty, c =>
{
c.Timeout = TimeSpan.FromMinutes(2);
});
// 配置特定客户端
options.AddHttpClient("github", c =>
{
c.Timeout = TimeSpan.FromMinutes(2);
});
问题修复
-
4.5.9+版本新增的IncludeScopes配置导致日志上下文失效 4.6.0 4a76841 - 多个
sql共用DbParameters出现冲突问题 4.6.0 #I5UO2H - 高频率写入日志导致堆内存溢出的异常问题 4.6.0 #I5UJRS
- 框架内部所有使用
.CreateLogger创建的日志对象无法应用上下文问题 4.6.0 ec4838c - 修复远程请求不能在
Worker Serivce中进行构造函数注入,原因是注册为Scope范围作用域 4.6.3 974f835 - 个别服务器的
SQL Server不支持TLS 1.2协议问题 4.6.3 974f835 -
.ToDictionary()拓展不支持JObject类型问题 4.6.5 #I5VJHC a11bf8d -
LoggingMonitor处理long类型丢精度问题 4.6.5 #I5VJHC aded58d - 动态
WebAPI在class类型上贴[ApiDescriptionSettings(false)]导致接口404问题 4.6.7 #I5WQ18 - 超高频率下发送事件总线消息,但是
GC来不及回收导致内存和CPU爆掉问题 4.6.8 dbc7935 -
JWT模块自动刷新Token达到临界值时导致自动刷新失败,并返回错误的401状态码 4.6.8 #I5WXHZ - 自动生成
vue/react/angular客户端工具库错误处理Token问题 4.6.8 #I5WXHZ - 远程请求没有正确处理
数组和集合类型的url参数 4.6.9 #I5XIQ4 - 自定义
Tenant实体且包含TenantId属性且没有继承EntityBase/Entity基类出现The entity type 'Tenant' requires a primary key to be defined4.6.9 #I4UM3E
-
其他更改
文档
- 远程请求设置客户端生命周期配置文档和新超时配置文档
-
JSON序列化处理long类型说明文档 -
JSON反序列化DateTimeOffset类型个别格式出错问题解决方案文档 -
Worker Service实现串行操作文档 - 关闭
.NET Core底层日志和远程请求日志文档 - 规范化结果支持特定接口配置独立序列化配置文档
- 日志记录文档、事件总线文档、数据库入门文档、
JSON序列化文档、远程请求文档、安全授权文档、生成前端请求代理文档
v4.5.9(已发布)
v4.5.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5ULWN 2022.10.09v4.5.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UGNS 2022.10.08v4.5.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U8Q9 2022.10.06v4.5.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U4SG 2022.10.03v4.5.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U413 2022.10.02v4.5.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U3MK 2022.10.01v4.5.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TXON 2022.09.30v4.5.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TLI6 2022.09.28v4.5.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TD4X 2022.09.27
新特性
-
.AddConsoleFormatter()拓展简化控制台日志模板配置 4.5.0 #I5TCMO - 控制台和文件日志时间默认显示
星期几4.5.1 #I5TKL5 - 控制台和文件日志支持配置
options.DateFormat日期格式化 4.5.1 #I5TKL5 - 控制台日志带颜色输出,比如高亮
日志级别4.5.1 #I5TKL5 - 控制台格式化配置
options.WriteHandler完全自定义配置 4.5.2 7fb3036 - 日志输出
JSON格式化配置 4.5.2 #I5TWC1 #I5OUT1 - 数据库日志写入独立日志模板配置、独立日期格式配置 4.5.2 #I5TWC1
-
LogMessage结构类LogDateTime,ThreadId,State属性 4.5.2 #I5TWC1 -
LoggingMonitor可配置JsonWriterOptions属性 4.5.4 #I5U375 -
Log.ScopeContext和"some log".ScopeContext拓展 4.5.4 8129693 - 新增
HttpContext.SetTokensOfResponseHeaders拓展 4.5.7 3775e65 - 新增远程请求支持
Stream文件格式上传 4.5.8 #I5UF3I - 日志模块可配置是否启用上下文功能
IncludeScopes属性 4.5.9 #I5UJRS -
LoggingMonitor日志筛选WriteFilter配置 4.5.9 6f06f12
-
突破性变化
- 😊
Furion框架文档地址为 https://furion.baiqian.ltd 4.5.4 2e3d80e -
LoggingMonitor底层逻辑,移除原来的.ScopeContext存储监听信息设计 4.5.2 #I5TWC1 -
主机未启动时构建服务的操作权限,此操作会导致内存激增,受影响方法:4.5.4 #I5U0A4 8129693App.GetOptions系列和App.GetService和Scoped.Create
- 😊
查看更改
近期发现许多开发者在主机还未启动时解析服务,这是非常不正确的行为,会导致启动时内存激增甚至溢出,常见的错误有:
- 在启动的时候通过
Scoped.Create创建作用域 - 在启动的时候通过
App.GetOptions获取选项对象 - 在启动的时候通过
App.GetService<T>解析服务
正确的做法是,启动的时候禁止使用 Scoped.Create 和 App.GetService<T>。
如需启动时获取配置应该通过:App.GetConfig<TOptions>("配置节点", true) 替代 App.GetOptions<TOptions>()。
问题修复
- 字符串日志拓展带泛型方法不能正确显示
CategoryName日志类别 4.5.0 #I5TBKL - 控制台日志设置了
.ScopeContext无效问题 4.5.2 7fb3036 -
LoggingMonitor同时配置了局部和全局日志监听触发两次问题 4.5.2 a1a97e8 -
v4.4.8+版本更新导致远程请求在个别情况下出现并发问题 4.5.2 #I5TWL3 -
LoggingMonitor配置了ReturnValueThreshold之后Json被截断引发有效性检测异常 4.5.4 #I5U375 -
LoggingMonitor不支持DataTable,DataSet,Tuple等类型问题 4.5.5 #I5U3VO - 自
v4.5.2+版本升级后出现启动时使用App.GetOptons<TOptions>异常问题 4.5.6 #I5U4OC f9a6587 -
app.UseInject(action)导致死循环 4.5.7 !608 -
LoggingMonitor报空引用异常问题 4.5.8 #I5UGCA !610 - 并发情况下设置日志上下文出现偶然性空引用问题 4.5.9 #I5UJRS
- 字符串日志拓展带泛型方法不能正确显示
其他更改
文档
- 选项监听出现触发多次的解决方案 #I5T9PR
- 日志记录文档、动态 WebAPI 文档、选项文档、
HttpContext文档、远程请求文档
本期亮点
- 支持日志配置
JSON格式化输出
- 支持日志配置
查看更改
// 控制台
services.AddConsoleFormatter(options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
// 文件
services.AddFileLogging("mytemplate.log", options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
// 数据库
services.AddDatabaseLogging<DatabaseLoggingWriter>(options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
- 支持
LoggingMonitor输出JSON格式
- 支持
查看更改
- 全局/局部启用
Json输出配置
// 全局
services.AddMonitorLogging(options =>
{
options.JsonBehavior = Furion.Logging.JsonBehavior.OnlyJson;
});
// 局部
[LoggingMonitor(JsonBehavior = Furion.Logging.JsonBehavior.OnlyJson)]
JsonBehavior只有设置为 JsonBehavior.OnlyJson 时才不会输出美观的日志。
- 写入存储介质
using Furion.Logging;
namespace Your.Core;
public class DatabaseLoggingWriter : IDatabaseLoggingWriter
{
// 支持构造函数注入任何实例,会自动释放任何服务,比如注入 IRepository,或者 SqlSugarClient
public DatabaseLoggingWriter()
{
}
public void Write(LogMessage logMsg, bool flush)
{
// 如果 JsonBehavior 配置为 OnlyJson 或者 All,那么 Context 就包含 loggingMonitor 的值
// 如果 JsonBehavior 配置为 OnlyJson,那么可直接通过 logMsg.Message 获取结果就是 json 格式
if (logMsg.LogName == "System.Logging.LoggingMonitor")
{
var jsonString = logMsg.Context.Get("loggingMonitor");
}
// 这里写你任何插入数据库的操作,无需 try catch
}
}
Json 输出格式如下:
{
"controllerName": "test-logger",
"controllerTypeName": "TestLoggerServices",
"actionName": "person",
"actionTypeName": "GetPerson",
"areaName": null,
"displayName": "Furion.Application.TestLoggerServices.GetPerson (Furion.Application)",
"localIPv4": "0.0.0.1",
"remoteIPv4": "0.0.0.1",
"httpMethod": "GET",
"requestUrl": "https://localhost:5001/api/test-logger/person/2",
"refererUrl": "https://localhost:5001/api/index.html?urls.primaryName=数据库操作演示",
"environment": "Development",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.53",
"requestHeaderAuthorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjEsIkFjY291bnQiOiJhZG1pbiIsImlhdCI6MTY2NDQ1MDUwNSwibmJmIjoxNjY0NDUwNTA1LCJleHAiOjE2NjQ0NTE3MDUsImlzcyI6ImRvdG5ldGNoaW5hIiwiYXVkIjoicG93ZXJieSBGdXJpb24ifQ.-xocNcDQGoXClceoVU5QAHIkTcOZ7ZXo0hEbzghDfFI",
"timeOperationElapsedMilliseconds": 55,
"authorizationClaims": [
{
"type": "UserId",
"valueType": "integer",
"value": "1"
},
{
"type": "Account",
"valueType": "string",
"value": "admin"
},
{
"type": "iat",
"valueType": "integer",
"value": "1664450505"
},
{
"type": "nbf",
"valueType": "integer",
"value": "1664450505"
},
{
"type": "exp",
"valueType": "integer",
"value": "1664451705"
},
{
"type": "iss",
"valueType": "string",
"value": "dotnetchina"
},
{
"type": "aud",
"valueType": "string",
"value": "powerby Furion"
}
],
"parameters": [
{
"name": "id",
"type": "System.Int32",
"value": 2
}
],
"returnInformation": {
"type": "Furion.UnifyResult.RESTfulResult`1[[System.Object, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
"actType": "Furion.Application.Persons.PersonDto",
"value": {
"StatusCode": 200,
"Data": {
"Id": 2,
"Name": null,
"Age": 0,
"Address": null,
"PhoneNumber": null,
"QQ": null,
"CreatedTime": "0001-01-01T00:00:00+00:00",
"Childrens": null,
"Posts": null
},
"Succeeded": true,
"Errors": null,
"Extras": null,
"Timestamp": 1664450517341
}
},
"exception": {
"type": "System.DivideByZeroException",
"message": "Attempted to divide by zero.",
"stackTrace": " at Furion.Application.TestLoggerServices.测试日志监听8(Int32 id) in D:\\Workplaces\\OpenSources\\Furion\\samples\\Furion.Application\\TestLoggerServices.cs:line 78\r\n at lambda_method103(Closure , Object , Object[] )\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)"
},
"validation": {
"errorCode": null,
"originErrorCode": null,
"message": "出错了啊。。。。"
}
}
- 支持远程请求上传文件
Stream流
- 支持远程请求上传文件
查看更改
- 单文件上传
- 字符串方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await "https://localhost:44316/api/test-module/upload-file"
.SetContentType("multipart/form-data")
.SetFiles(HttpFile.Create("file", fileStream, "image.png")).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 代理方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await _http.TestSingleFileProxyAsync(HttpFile.Create("file", fileStream, "image.png"));
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 多文件上传
- 字符串方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await "https://localhost:44316/api/test-module/upload-muliti-file"
.SetContentType("multipart/form-data")
.SetFiles(HttpFile.CreateMultiple("files", (fileStream, "image1.png"), (fileStream, "image2.png"))).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 代理方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await _http.TestMultiFileProxyAsync(HttpFile.CreateMultiple("files", (fileStream, "image1.png"), (fileStream, "image2.png")));
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 还支持
Bytes和Stream混合
var fileStream = new FileStream("image.png", FileMode.Open);
var bytes = File.ReadAllBytes("image.png");
var httpFile = new HttpFile
{
Name = name,
Bytes = bytes,
FileStream = fileStream,
FileName = fileName
};
var result = await "https://localhost:44316/api/test-module/upload-file"
.SetContentType("multipart/form-data")
.SetFiles(httpFile).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
LoggingMonitor全局过滤
查看更改
services.AddMonitorLogging(options =>
{
options.WriteFilter = (context) =>
{
// 获取控制器/操作描述器
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
// 你的逻辑....,不需要拦截返回 false,否则 true
return true;
};
});
v4.4.9(已发布)
v4.4.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SP37 2022.09.23v4.4.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SKUE 2022.09.22v4.4.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SEFE 2022.09.21v4.4.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5RSFD 2022.09.19v4.4.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5RHQX 2022.09.16v4.4.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5R5TI 2022.09.15v4.4.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5QVH3 2022.09.13v4.4.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5QDHX 2022.09.08v4.4.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Q3SX 2022.09.07v4.4.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PQHR 2022.09.05
新特性
- 友好异常可控制是否输出错误日志配置
LogError: true4.4.0 #I5PKJH -
DateOnlyJsonConverter和DateOnlyOffsetJsonConverter序列化转换器 !565 - 事件总线
LogEnabled配置,可控制是否输出服务日志 #I5QLY5 - 可实现任何多套规范化结果功能,支持特定控制器,特定方法 #I5QZ37
-
ILoggerFactory日志工厂动态批量添加文件日志拓展 #I5R9PO -
App.GetCommandLineConfiguration(args)解析命令行参数静态方法 803542c -
Sql代理支持返回受影响行数 #I5REJ9 - 任意自定义日志文件名支持滚动日志删除功能 #I5RFBQ
-
.pcd图片类型MIME为image/x-photo-cd支持 5fafc84 - 默认日志输出当前线程
Environment.CurrentManagedThreadIdb8fe2cd -
app.UseInject(Action<UseInjectOptions>)重载方法,简化配置 4.4.8 0b645fe
- 友好异常可控制是否输出错误日志配置
突破性变化
查看更改
public interface IHttp : IHttpDispatchProxy
{
[Post("https://www.furion.icu/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(HttpFile file);
// 支持多个文件
[Post("https://www.furion.icu/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(HttpFile[] files);
// 支持多个文件
[Post("https://www.furion.icu/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(IList<HttpFile> files);
}
// bytes 可以通过 File.ReadAllBytes(文件路径) 获取
var res = await "https://www.furion.icu/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.Create("file", bytes, "image.png")).PostAsync();
// 支持多个文件
var res = await "https://www.furion.icu/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.CreateMultiple("files", (bytes, "image1.png"), (bytes, "image2.png"))).PostAsync();
- 所有的
AddInject和UseInject参数设计 #I5QCF0
- 所有的
查看更改
public void ConfigureServices(IServiceCollection services)
{
services.AddInject(options =>
{
options.ConfigureSwaggerGen(gen =>
{
// ...
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseInject(configure: options =>
{
options.ConfigureSwagger(swg =>
{
// ...
});
options.ConfigureSwaggerUI(ui =>
{
// ...
});
});
}
- 远程请求所有
xxxAsStreamAsync返回值 #I5QVEB
- 远程请求所有
查看更改
由:
var stream = await "https://www.furion.icu/".GetAsStreamAsync();
改为:
var (stream, encoding) = await "https://www.furion.icu/".GetAsStreamAsync();
-
.Inject()支持配置更多参数,开放底层更多权限 4.4.9 1182283
-
查看更改
.Inject((builder, options) => {
options.ConfigureAppConfiguration((context, config) =>
{
});
options.ConfigureServices((context, services) =>
{
});
});
问题修复
- 远程请求代理模式非泛型参数导致数组溢出问题 #I5Q3SN
-
LoggingMonitor客户端IP记录错误 #I5QCU1 !562 - 远程请求响应报文中包含
charset=gbk进行序列化后乱码问题 #I5QVEB - 文件日志断电时丢失日志问题 db7d51b
- 动态
WebAPI或控制台贴了[ApiDescriptionSettings(Tag = "")]标签之后导致注释丢失 #I5REVF #I5RE4J - 启用数据库日志但是没有配置配置文件出现空异常问题 33817be
- 控制台日志过滤无法过滤默认主机日志问题 33817be
- 脚手架错误的日志配置问题 33817be
- 高频压测情况下写日志并设置日志上下文导致并发更新出现
System.AggregateException异常问题 #I5RFBQ - 日志文件名因
Windows和Linux路径分隔符不一致导致日志文件创建失败问题,Linux只支持/不支持\#I5RFBQ -
Oops.Oh/Bah设置.WithData之后无效问题 !580 - 基于
Redis重写事件存储器序列化IEventSource实例异常问题 4.4.7 3e45020 - 使用
Log静态类超高频率下写日志导致CPU激增问题 4.4.7 #I5SDK5 - 远程请求超高频率下发送请求导致
CPU激增问题和异常问题 4.4.8 #I5SJJR - 集成第三方配置中心时获取的不是最新数据问题 4.4.9 2cdef6b
其他更改
文档
-
.NET6升级.NET7文档 -
ASP.NET 7集成文档 - 集成第三方配置中心文档 4.4.9
- 第三方事件总线和
Furion集成文档 4.4.9 - 事件总线集成
Kafka文档 #I5P5UG - 友好异常文档、日志记录文档、远程请求文档、依赖注入文档、即时通讯文档、事件总线文档、Worker Service 文档、单元测试文档、入门指南文档、数据库新增文档
-
v4.3.9(已发布)
v4.3.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PIWD 2022.09.03v4.3.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PCXK 2022.09.02
新特性
-
AppSettings配置的ExcludeAssemblies属性,支持忽略指定程序集扫描 7b7747f -
Oops.Oh和Oops.Bah支持设置额外数据.WithData(data)#I5O38E - 定时任务
Crontab.GetSleepMilliseconds(baseTime)获取下一个发生时间的时间差 d024fae - 友好异常默认打印异常日志,避免生产环境漏掉重要异常信息 6e3a5bd
- 日志静态类
Log.CreateLoggerFactory()静态方法 75c672a - 多语言
SharedResource模式,避免硬编程 18e80c7 - 事件总线
MessageCenter静态类,解决从Fur v1.x版本升级问题 a29fc7c - 组件化
IWebComponent模式,支持.NET5+08a44c3 - 远程请求设置自己的
HttpClient功能 #I5PBR3 !545 -
LoggingMonitor支持添加更多自定义配置 #I5PEPA -
LoggingMonitor可配置WithReturnValue和ReturnValueThreshold#I5PFJ1 #I5PFOW -
LoggingMonitor可配置MethodsSettings更多信息 #I5PFJ1 #I5PFOW
-
查看更改
Serve.Run(RunOptions.Default
.AddWebComponent<XXXWebComponent>());
public class XXXWebComponent : IWebComponent
{
public void Load(WebApplicationBuilder builder, ComponentContext componentContext)
{
// ....
}
}
突破性变化
查看更改
[Interceptor(InterceptorTypes.Request)]
static void OnRequest(HttpClient client, HttpRequestMessage req)
{
}
[Interceptor(InterceptorTypes.Response)]
static void OnResponsing(HttpClien client, HttpResponseMessage res)
{
}
[Interceptor(InterceptorTypes.Exception)]
static void OnException(HttpClient client, HttpResponseMessage res, string errors)
{
}
问题修复
其他更改
文档
-
RabbitMQ事件总线文档 -
AppSettings配置文档、事件总线文档、多数据库配置文档、日志文档、定时任务文档、MessageCenter文档、远程请求文档、组件化文档、入门指南、多语言文档。
-
v4.2.13(已发布)
新特性
- 事件总线工厂,支持运行时动态添加订阅程序和移除订阅程序 #I5NNQX
- 事件总线
[EventSubscribe]事件Id支持正则表达式匹配 #I5NNQX - 事件总线
[EventSubscribe]支持局部失败重试配置 #I5NNQX -
Log全局静态类,方便随时随地记录日志 ba9b1f1 - 事件总线
options.AddSubscriber(Type)重载 42446078 -
ValidationMetadata类型FirstErrorProperty和FirstErrorMessage属性 #I5MFJT -
Serve.Run()模式WithArgs(args)方法 #I5MOJB -
[UnitOfWork]分布式事务TransactionScope支持 #I5MRTY - 16 位
MD5加密支持 #I5N8RC
突破性变化
-
Scoped.Create(async (f,s) => {})异步创建作用域方法名称为CreateAsync,避免一些情况下无法区分,同步方法不变 #I5N9XY
-
查看更改
由:
// Scoped.CreateUow 一样
await Scoped.Create(async (f, s) => {});
改为:
// Scoped.CreateUowAsync 一样
await Scoped.CreateAsync(async (f, s) => {});
-
.NET 6.0.8和.NET 7 Preview 7842d4f7
-
-
[LoggingMonitor]命名空间为System,因为使用频率越来越高 b879861
-
- 在非
Web环境中不正确使用字符串拓展方法检测机制 6389cbd
- 在非
- 所有
.Default静态属性为.Default()方法 6389cbd
- 所有
- 工作单元
IUnitOfWork所有方法参数类型,由ActionExecutingContext和ActionExecutedContext改为FilterContext#I5MHX5
- 工作单元
查看更改
public interface IUnitOfWork
{
void BeginTransaction(FilterContext context, UnitOfWorkAttribute unitOfWork);
void CommitTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork);
void RollbackTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork);
void OnCompleted(FilterContext context, FilterContext resultContext);
}
问题修复
- 日志上下文数据多次写入被清空问题以及数据库日志出现异常后停止写入 #I5LIWF
- 个别情况下跨域默认配置的响应缓存导致嵌入式资源异常问题 7a57efe
- 远程请求传入不合法的请求报文头数据触发校验失败问题 #I5LPFE
- 多线程中使用静态日志写数据库日志导致连接池耗光问题 8d5cdd6
-
EFCore 6.0之后IModelCacheKeyFactory接口方法改变导致分表分库异常问题 #I5MCZ6 EFCore#25154 EFCore!3305 -
ValidationMetadata对象Message字符串类型出现\"\"问题 #I5MFJT -
[IfException]覆盖Oops.Oh/Bah错误消息问题 4bbd854 - 数据库日志写入循环写入和频繁创建数据库连接池问题 9ce214c
-
Razor Pages不支持全局异常拦截问题 #I5MHX5 -
Razor Pages不支持全局数据验证问题 #I5MHX5 -
Razor Pages不支持工作单元[UnitOfWork]问题 #I5MHX5 -
Razor Pages不支持EFCore自动SaveChanges问题 #I5MHX5 -
Blazor Server因v4.2.2版本更新导致的问题 #I5MNFN -
[IfException]不支持多语言配置问题 #I5MPN7 - 通过
services.AddMvcFilter<LoggingMonitorAttribute>()方式注册无效问题 8d1477d - 事件总线默认
Channel管道初始化时机过晚问题,解决部分第三方依赖使用问题 #I5MM3O - 主机停止时写入日志异常问题 #I5N7S2
- 数据库上下文手动释放导致
AutoSaveChange特性出现释放异常问题 #I5NFWC -
[LoggingMonitor]循环引用序列化问题 #I5NRT9 - 远程请求传入
nullBody 参数抛出空异常问题 #I5NTUE - 事件总线默认开启模糊匹配(正则表达式)导致不必要的订阅 #I5NVOP
其他更改
文档
- 全局日志静态类
Log文档 ba9b1f1 -
Nuget本地测试包文档 - 日志文档、静态类文档、数据校验文档、Worker Service 文档、工作单元文档、依赖注入文档
- 全局日志静态类
v4.1.14(已发布)
新特性
-
Furion.Xunit拓展包,正式实现Xunit单元测试完整支持Furion063a034e -
services.AddMonitorLogging()日志监视器服务,支持非常灵活的日志操作 81df742 -
Serve.Run(silence: true)等一系列强大的静默启动功能 #I5JBSQ #I5J98T 7cced4 -
SpecificationDocumentBuilder.GetOpenApiGroups()方法获取底层的规范化接口分组信息 4ff03c5 -
logger.ScopeContext()配置日志上下文功能 #I5JC0D - 跨域配置
CorsAccessorSettings.SignalRSupport配置选项,支持配置SignalR跨域 #I5JREM - 事件总线
UseUtcTimestamp选项配置,可选择使用DateTime.UtcNow还是DateTime.Now,默认是DateTime.Now#I5JSEU - 规范化文档
[OperationId]配置,解决自定义Swagger UI不能正确显示路由问题 #I5K1IB - 远程请求
IHttpDispatchProxy方式全局拦截支持多态(继承) #I5K8FS
-
突破性变化
-
Furion.Xunit拓展包,正式实现Xunit单元测试完整支持Furion063a034e -
查看最新实现文档**Furion.Extras.DatabaseAccessor.SqlSugar拓展插件中的[SqlSugarUnitOfWork]工作单元特性,将使用通用工作单元替换** -
200848eInject.Create()方法,再也不需要了,框架提供了无敌强大的Serve.Run()静默启动方式 -
Serve.Run的ConfigureConfiguration方法参数,由configuration => {}改为(environment, configuration) => {}83c97bb
-
查看更改
// 由
Serve.Run(RunOptions.Default.ConfigureConfiguration(configuration => {
}));
// 改为:
Serve.Run(RunOptions.Default.ConfigureConfiguration((environment, configuration) => {
}));
问题修复
-
[LoggingMonitor]异常消息日志级别为Information错误问题 ab46cdf - 新版本日志组件频繁提示文件占用问题,将文件独占锁改为共享锁 #I5J3S6
- 配置数据库日志读写器为
EFCore时控制台出现无限打印问题 #I5J474 -
[LoggingMonitor]针对byte[]类型参数输出过大问题 5380f35 - 友好异常和规范化结果丢失了原始
ErrorCode问题 #I5IX2R - 新版本日志组件自定义数据库读写器注入
IRepository仓储导致死循环问题 #I5IX2R -
Mvc默认手动验证和Furion全局验证冲突问题 2a06c39 -
Serve.Run()模式不支持SuperSocket第三方包问题,原生是支持的。186ca0a -
SignalR跨域错误问题 #I5JREM -
[LoggingMonitor]将Oops.Oh和Oops.Bah记录到了错误日志中,默认应该是Information且提供可配置 #I5JZ1H - 自定义
Swagger UI之后个别UI要求必须配置operationId,否则出现guid序号 #I5K1IB - 主动抛出
NotFoundResult和NotFoundObjectResult无效问题 #I5KALZ -
[LoggingMonitor]解析方法参数但前端未传入时出现错误问题 #I5KC5P -
[LoggingMonitor]无法序列化IQueryable返回值问题 #I5KJD1 -
[LoggingMonitor]不能记录全局验证错误问题 b44087d -
[LoggingMonitor]存在注册顺序差异问题 b44087d
-
其他更改
- 底层的规范化文档
SpecificationDocumentBuilder部分方法,提供更加便捷的第三方Swagger UI集成 10f0f01
- 底层的规范化文档
文档
- 单元测试文档、入门指南文档、Worker Services 文档
本期亮点
Serve.Run()彻彻底底支持全平台,提供非常强大的静默模式
启用静默模式可以实现无阻塞方式执行程序,而且还能体验完整的 Furion 功能。
查看更改
有了 Serve.Run() 静默模式后,Furion 彻彻底底支持全平台,不管你是 控制台、Web、桌面、移动、单元测试,集成测试,基准测试等等应用程序。
Serve.Run(silence: true);
// 不会阻塞执行哦,而且从这里开始可以使用 Furion 任何功能,比如 App.Configuration....
Console.WriteLine("Hello, World!");
Console.ReadKey();
还有更多静默模式。
// RunOptions 方式
Serve.Run(RunOptions.DefaultSilence);
// LegacyRunOptions 方式
Serve.Run(LegacyRunOptions.DefaultSilence);
// GenericRunOptions 方式
Serve.Run(GenericRunOptions.DefaultSilence);
- 强大的
Furion.Xunit单元测试、集成测试
查看更改
单元测试和集成测试是保证一个系统能够持续维护和稳定运行的必备技能,但是目前现有的单元测试组件无法直接集成 Furion 的功能,最常用的就是如何在单元测试中读取配置,以及如何进行依赖注入。
在过去,Furion 只能不断的去调整,以至于适配第三方单元测试写法,搞得不伦不类!
所以,这一次不再妥协,Furion 推出自己的单元测试工具,可以让现有的单元测试如 Xunit 100% 支持 Furion 所有功能,全部保证一致的写法。
单元测试中初始化 Furion
using Furion.Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
// 配置启动类类型,第一个参数是 TestProgram 类完整限定名,第二个参数是当前项目程序集名称
[assembly: TestFramework("TestProject1.TestProgram", "TestProject1")]
namespace TestProject1;
/// <summary>
/// 单元测试启动类
/// </summary>
public class TestProgram : TestStartup
{
public TestProgram(IMessageSink messageSink) : base(messageSink)
{
// 初始化 Furion
Serve.Run(silence: true);
}
}
测试类支持完整依赖注入
using TestProject1.Services;
using Xunit;
namespace TestProject1;
public class UnitTest1
{
private readonly ICalcService _calcService;
public UnitTest1(ICalcService calcService)
{
_calcService = calcService;
}
[Fact]
public void 测试两个数的和()
{
Assert.Equal(3, _calcService.Plus(1, 2));
}
}

- 开放底层规范化文档分组接口,使得集成第三方
Swagger UI更加容易,如集成IGeekFan.AspNetCore.Knife4jUI拓展:
查看更改
只需要在 YourPoject.Web.Core 层安装 IGeekFan.AspNetCore.Knife4jUI 即可。
3.1.1 Knife4jUI 独立版本配置
var routePrefix = "api"; // 定义 swagger 路由地址,如果是跟目录,设置 string.Empty 即可
app.UseKnife4UI(options =>
{
options.RoutePrefix = routePrefix; // 配置 Knife4UI 路由地址
foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
{
options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
}
});
app.UseInject(routePrefix); // 配置 Furion 路由地址
3.1.2 Knife4jUI 和 Swagger 共存版本配置
app.UseKnife4UI(options =>
{
options.RoutePrefix = "newapi"; // 配置 Knife4UI 路由地址,现在是 /newapi
foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
{
options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
}
});
app.UseInject(); // Furion 默认 api 地址为 /api

如需实现登录之后自动将 token 添加到头部可在登录接口 AfterScript 执行以下代码:
ke.global.setAllHeader(
"Authorization",
"Bearer " + ke.response.headers["access-token"]
);

- 提供强大的日志上下文功能
// 写法一
_logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10))
.LogInformation("我是一个日志 {id}", 20);
// 写法二
_logger.ScopeContext(new Dictionary<object, object> {
{ "Name", "Furion" },
{ "UserId", 10 }
}).LogInformation("我是一个日志 {id}", 20);
// 写法三
_logger.ScopeContext(new LogContext {
// ....
}).LogInformation("我是一个日志 {id}", 20)
v4.0.0(重新起航)💖
2020 年 09 月 01 日,一个叫 Fur 的开源项目在 Gitee 的襁褓中悄然诞生,她的出生仿佛带着某种使命,没有包袱,无限可能。
她缓缓的张开双眼,干净雪亮的眼睛似乎对这个世界充满了好奇,任何事物在她眼前晃过都像是直击灵魂的思想碰撞,这些在她看来都是非常宝贵的财富。她貌似有用不完的精力,一路汲取知识,升级打怪,不断奔跑,乐此不疲。
记得 2020 年 11 月 11 日的单身节,她迎来了“一岁(v1.0.0)”生日,自那以后,IT 这个大银幕上频繁出现她的身影,越来越多 .NET5 开发者转粉,像是告诉这个世界,她就是 IT 界大明星。
每一个明星都有一个好听的艺名,她当然也不例外,2020 年 11 月 20 日,经纪人百小僧为她起名为 Furion。
2021 年 11 月 09 日起,她进入了每个孩子都经历过的叛逆期,年少轻狂喜新厌旧,抛弃了曾经支持她的 .NET5 粉丝们,投入到新的 .NET6 拥趸者怀抱中,自此过上了奢靡富足的生活。
但她过的不开心,时常在夜里想起 .NET5 的粉丝们,内心非常自责,但在双重工作压力下她毅然选择了忽视他们的诉求,仿佛他们就是累赘。
时间真的是好东西,曾经认为是对的,经过岁月的蹉跎历磨,渐渐的明白:不忘初心,方能始终。
这一次,不落下一人(.NET5,.NET6,...,.NET N),携手共进,重新起航,感恩遇见,感恩信任。
新特性
v4.0.0支持.NET5,.NET6,...,.NET N,所有的Furion项目都能够升级到该版本,重新起航,实现大统。
v3.9.2(已发布,全新日志组件)
日志模块是任何应用系统都必备的功能,可以说是最重要的模块!在 .NET 社区中有 Log4NET,NLog,Serilog 等日志组件,它们无一不是优秀的开源项目。
但由于这些日志组件历史悠久,内部兼容的 .NET 版本非常多,功能随着时间推移变得极其强大复杂,在实际项目使用中,发现每一个日志组件配置总是不那么友好,特别是在使用上不够简单。
Furion 作为全栈开发框架,在过去版本并没有提供足以满足开发者需求的日志模块,转而推荐大家集成第三方组件,如 Serilog,导致后续无法实现自定义功能和也增加了不少维护成本。
这一次,Furion 不再妥协,彻底重构了日志模块,实现日志功能/需求完全自主可控,提供给开发者几乎所有日志功能的需求!
Furion 的使用者们,是时候“更换”掉第三方日志组件,让我们一起迭代出更强更好的日志组件吧! 🍖
新特性
突破性变化
问题修复
- 修复脱敏模块模型绑定个别情况下空异常问题 #I5IM5C
文档
- 日志文档、静态类文档、数据校验文档
本期亮点
- 极易使用且强大的日志模块
查看更改
// 写入文件
services.AddFileLogging("logs/application.log");
// 写入数据库
services.AddDatabaseLogging<DatabaseLoggingWriter>();
- 强大的
[LoggingMonitor]调试日志
查看更改
using Furion.Logging;
namespace Furion.Application;
public class TestLoggerServices : IDynamicApiController
{
[LoggingMonitor]
public PersonDto GetPerson(int id)
{
return new PersonDto
{
Id = id
};
}
}
支持控制器、操作或全局注册拦截。
输出日志为:
┏━━━━━━━━━━━ Logging Monitor ━━━━━━━━━━━
┣ Furion.Application.TestLoggerServices.GetPerson (Furion.Application)
┣
┣ 控制器名称: TestLoggerServices
┣ 操作名称: GetPerson
┣ 路由信息: [area]: ; [controller]: test-logger; [action]: person
┣ 请求地址: https://localhost:44316/api/test-logger/person/11
┣ 来源地址: https://localhost:44316/api/index.html
┣ 浏览器标识: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62
┣ 客户端 IP 地址: 0.0.0.1
┣ 服务端 IP 地址: 0.0.0.1
┣ 服务端运行环境: Development
┣ 执行耗时: 31ms
┣ ━━━━━━━━━━━━━━━ 授权信息 ━━━━━━━━━━━━━━━
┣ JWT Token: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjEsIkFjY291bnQiOiJhZG1pbiIsImlhdCI6MTY1ODcxNjc5NywibmJmIjoxNjU4NzE2Nzk3LCJleHAiOjE2NTg3MTc5OTcsImlzcyI6ImRvdG5ldGNoaW5hIiwiYXVkIjoicG93ZXJieSBGdXJpb24ifQ.VYZkwwqCwlUy3aJjuL-og62I0rkxNQ96kSjEm3VgXtg
┣
┣ UserId (integer): 1
┣ Account (string): admin
┣ iat (integer): 1658716797
┣ nbf (integer): 1658716797
┣ exp (integer): 1658717997
┣ iss (string): dotnetchina
┣ aud (string): powerby Furion
┣ ━━━━━━━━━━━━━━━ 参数列表 ━━━━━━━━━━━━━━━
┣ Content-Type:
┣
┣ id (Int32): 11
┣ ━━━━━━━━━━━━━━━ 返回信息 ━━━━━━━━━━━━━━━
┣ 类型: Furion.Application.Persons.PersonDto
┣ 返回值: {"Id":11,"Name":null,"Age":0,"Address":null,"PhoneNumber":null,"QQ":null,"CreatedTime":"0001-01-01T00:00:00+00:00","Childrens":null,"Posts":null}
┗━━━━━━━━━━━ Logging Monitor ━━━━━━━━━━━
v3.8.9(已发布)
新特性
- 规范化结果
ExceptionMetadata和ValidationMetadata都可以获取ErrorCode属性 #I5GJ6D -
ValidationMetadata类StatusCode属性 #I5HB5L - 远程请求对
Url是否编码设置,[Get(WithEncodeUrl = false)]和WithEncodeUrl(false)#I5GOBC - 更强大的
JWTEncryption.SecurityReadJwtToken('token')读取解析Token静态方法 574eeb6 -
ValiationTypes.Html验证Html标签 #I5HBKC - EFCore.NamingConventions 支持,可自定义生成表名,字段名风格,比如小驼峰,蛇形命名等 #I5HBEI
-
INamedServiceProvider命名服务提供器,可解析接口多实现 #I5HF98 - 脱敏处理模块方法参数单个值处理 a22ec3c
- 脱敏词库支持
|分割词语 3106b1d
- 规范化结果
突破性变化
问题修复
-
Rider开发工具对同名脚手架 (EFCore和SqlSugar) 只显示一个问题 !518 -
UnitOfWork工作单元在EFCore中失效问题 #I5H0T3 -
JWT中Token如果存在数组类型的值时,刷新Token后丢失了历史值 #I5GXML - 远程请求
WithEncodeUrl无法在[HttpMethod]设置问题 574eeb6 -
Serve.Run()模式下添加自定义配置导致EFCore无法获取自定义配置文件问题 #I5GZ0F -
Oops.Bah进入全局异常拦截器问题 #I5H47S -
AddDbPool/AddDb扩展未根据配置Key路径读取问题 #I5H6S4 !520 -
ValiationTypes.Url正则表达式覆盖不全问题 #I5HBKC -
v3.5.x版本导致集成 EFCore.NamingConventions 失效问题 #I5HBEI -
Swagger长路由不支持问题以及[Required]配置AllowEmptyStrings无效问题 c014330 - 远程请求上传文件时请求报文
boundary和Content-Disposition设置不正确问题 #I5HEF0 - 脱敏模块替换敏感词汇出现多替换问题 a22ec3c
-
其他更改
文档
- 远程请求文档,日志记录文档、多数据库文档、PM2 部署文档、Visual Studio 高效率文档
v3.7.11(已发布)
新特性
-
Minimal API应用支持:.AddInjectMini()#I4KOQ5 - 跨域
WithExposedHeaders默认配置access-token和x-access-token42ebdfd - 脚手架默认启用
app.UseHttpLogging()HTTP日志 42ebdfd -
Furion和ASP.NET Core完整json配置的JSON Schema架构 JSON Schema -
Sql代理支持返回单个类类型参数 1d7fb5b -
Sql代理支持返回ValueTuple单个类类型参数 876a2f5 - 组件化设计模块,支持比
AppStartup更灵活便捷的设计 #components - 独立工作单元模块,支持任何第三方
ORMa02413d - 跨域
FixedClientToken配置参数 bd01638 -
throw Oops.Bah可以手动触发规范化验证失败处理 83f0036 -
FriendlyExceptionSettings的ThrowBah配置,可标记Oops.Oh不进入异常处理 76ffa7f
-
突破性变化
-
Minimal API应用支持:.AddInjectMini()#I4KOQ5 -
Furion和ASP.NET Core完整json配置的JSON Schema架构 JSON Schema - 组件化设计模块,支持比
AppStartup更灵活便捷的设计 #components - 独立工作单元单元模块,支持任何第三方
ORMa02413d -
DataValidationFilter和FriendlyExceptionFilter,解决不支持手动抛出业务异常问题 83f0036 -
.AddDb<>和.AddDbPool<>自定义委托参数签名,由Action<DbContextOptionsBuilder>改为:Action<IServiceProvider, DbContextOptionsBuilder>
-
查看更改
// 由:
options.AddDbPool<TDbContext>(DbProvider.MySql, opt => {
});
// 改为
options.AddDbPool<TDbContext>(DbProvider.MySql, (services, opt)=> {
})
问题修复
- 自
v3.6.3版本依赖,执行原生Sql添加了参数校验导致存储过程执行错误问题 #I5ERMQ -
tools/cli.ps1脚本工具出现数据库链接被占用问题 -
JWTSettings算法配置JSON Schema错误问题,感谢 @gitwentao #I5G27B !516 - 基于策略授权在不配置
Policy的情况下出现空异常问题 #I5EVF2 - 启用数据库实体跟踪时导致新增实体多次查询数据库问题 #I4J2LZ
- 不启用规范化结果导致验证失效,异常失效问题 cdb3f57
- 验证异常和友好异常冲突问题 83f0036
-
CentOS 7.9系统部署无法指定命令--urls参数问题 8cc8ee
- 自
其他更改
- 脚手架所有
.json文件,默认添加JSON Schema支持
- 脚手架所有
文档
- 组件化启动文档
-
Vue/React/Angular请求代理文档 -
JSON Schema文档,支持配置智能提示和验证 - 跨域文档、规范化文档、配置文档、日志文档、IIS 部署文档
本期亮点
- 新增
JSON Schema支持,所有.json文件支持智能提示和验证
查看更改
{
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"AllowedHosts": "*"
}

- 根据
Swagger生成Vue/React/Angular前端请求代码
Sql代理支持返回单个类类型参数
查看更改
public interface ISql : ISqlDispatchProxy
{
// 集合类型
[SqlExecute("select * from person")]
List<Person> GetPersons();
// 自 v3.7.3+ 版本支持返回单个类类型参数
[SqlExecute("select * from person where id=@id")]
Person GetPerson(int id);
}
Sql代理支持返回ValueTuple单个类类型参数
查看更改
public interface ISql : ISqlDispatchProxy
{
[SqlExecute(@"
select * from person where id =@id;
select * from person")]
(Person, List<Person>) GetData(int id); // 注意返回值是 `(Person, List<Person>)` 组合
}
- 支持
Minimal API应用
查看更改
var builder = WebApplication.CreateBuilder(args).Inject();
// 注册 Minimal 服务
builder.Services.AddInjectMini();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseInject(string.Empty);
app.MapGet("/hello", () =>
{
return "Hello, Furion";
});
app.Run();
v3.6.9(已发布,全新入口组件)
新特性
-
Serve.Run()极简主机模式,真正实现极速入门。95cac5b -
TP.Wrapper(...)拓展方法,主要用来生成规范化的日志模板 427999a - 项目类型为
<Project Sdk="Microsoft.NET.Sdk">的控制台项目 fb08a65 -
BadPageResult错误页面类型 !494 -
[SchemaId]特性,解决不同程序集相同的类名生成Swagger的SchemaId冲突问题 #I5D3CU - 远程请求
options.ApproveAllCerts()忽略所有客户端证书拓展 eb7d18a - 判断是否是单文件环境部署静态属性
App.SingleFileEnvironmentde556f0 -
WebApplicationBuilder.UseSerilogDefault()拓展 e02524c
-
突破性变化
问题修复
- 修复默认注册的
services.AddResponseCaching();服务导致.axd内嵌资源请求错误问题 !495 -
Oracle数据库执行sql必须要求命令参数和sql语言参数数量一致 #I5D057 -
IHostService类型不能自动注册问题,之前只扫描了BackgroundService派生类 968344 - 国产芯片主机不能识别
dotnet run --urls参数问题 6d4398 - 远程请求上传文件不支持特定文件后缀问题,如
.pem文件 ba42198 - 一些程序集已破坏或程序集不完整导致主机无法启动问题 d2dc3e4
- 远程请求传入
headers时类型为Dictionary<string, string>导致转换异常问题 #I5DHL9 -
Serilog单文件发布不生成日志文件 I5DQ2B
- 修复默认注册的
其他更改
文档
-
Serve.Run()文档 -
HttpContext文档 -
GlobalUsings文档 -
TP全局静态类文档 - 中间件文档、筛选器文档、审计日志文档
- 跨域文档、远程请求文档
-
精彩贡献
- !494 优秀
Pull Request辩论典范
- !494 优秀
本期亮点
- 极速入门
查看更改
Serve.Run();
[DynamicApiController]
public class HelloService
{
public string Say()
{
return "Hello, Furion";
}
}
启动浏览器查看效果,惊呆了吗!

- 内置错误页
查看更改
using Furion.FriendlyException;
public IActionResult Add(Person person)
{
if(!ModelState.IsValid)
{
return new BadPageResult();
}
}

Swagger支持Markdown
查看更改
/// <summary>
/// 测试 Markdown
/// </summary>
/// <remarks>
/// # 测试 `Markdown` 注释
///
/// 
///
/// ```cs
/// Serve.Run();
///
/// [DynamicApiController
/// public class HelloService
/// {
/// public string Say()
/// {
/// return nameof(Furion);
/// }
/// }
/// ```
///
/// 功能还不错!!!
///
/// | 商品 | 价格 | # 其他 |
/// |--------------|-----------|------------|
/// | Juicy Apples | 1.99 | *7* |
/// | Bananas | **1.89** | 5234 |
/// | Bananas | **1.89** | 5234 |
/// | Bananas | **1.89** | 5234 |
///
/// -----
///
/// # Furion 探索版
///
/// > 在过去一年,实现 `Furion` 从无到有,编写文档已逾百万字,过程心酸开源人自知。
/// >
/// > 这一路日夜兼程,嘲讽批评常伴眼耳,即便辛苦无奈、想过放弃,但为了那微不足道的存在感依然努力着。
/// >
/// > 当然,也收获了不少...越来越多拥趸者,越发精湛技术能力,更高层次思维模式,还有许多跨界跨行朋友。
/// >
/// > 在 《[开源指北] (https://gitee.com/opensource-guide/comments/)》中,我曾说道:“开源如同人的脸,好坏一面便知,缺点可能会受到嘲讽批评,优点也会收获赞扬尊重。别担心,他们正在塑造更好的你。”
/// >
/// > 所以,这一次重新起航,重塑 `Furion` 重塑自己。也许未来在某个 IT 圈但凡有人谈起 `.NET` 还能瞟到 `Furion` 的身影。
///
/// ---
///
/// 🎉 探索 Furion 未来更多可能性,实现无第三方依赖的版本,所有模块功能按需安装,按需加载。
///
/// - 作者:[百小僧] (https://gitee.com/monksoul)
/// - 日期:2021 年 08 月 30 日
///
/// ## 环境
///
/// - IDE :[Microsoft Visual Studio Enterprise 2022 Preview(64 位) 版本 17.0.0 Preview 3.1] (https://visualstudio.microsoft.com/zh-hans/vs/preview/)
/// - SDK :[.NET SDK 6] (https://dotnet.microsoft.com/download/dotnet/6.0)
/// - 语言:[C# 10](https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-10)
///
/// ## 包说明
///
/// - `Furion.Core`:无第三方依赖,可在 `.NET 6` 所有项目类型中运行。
/// - `Furion`:内部依赖 `Furion.Core` 且无第三方依赖,**聚焦 `Web` 应用**,采用共享框架 `<FrameworkReference Include="Microsoft.AspNetCore.App" />` 模式
/// </remarks>
public void MarkdownTest()
{
// ....
}

v3.5.7(已发布)
新特性
-
Options选项属性支持自定义Key名称,[MapSettings("key")]#I5B2HN -
EventBus模块事件Id支持枚举类型 2f328aa -
EventBus模块发布者PublishAsync和PublishDelayAsync重载 2f328aa -
EventBus模块拓展方法:Enum.ParseToString()和String.ParseToEnum()2f328aa -
Furion和SqlSugar脚手架 🆕🆕🆕 8d9293d -
Dapper拓展全局配置委托 #I5AYFX -
sql转实体支持多种命名策略(纯大写,纯小写,带下划线分割等等),如Oracle数据库 a90e245 -
FS.InitalContentTypeProvider()拓展方法,获取系统内所有支持的Content-Type文件提供器 6099900
-
突破性变化
- 彻底解决了
Furion不能单文件发布的问题 7e8e0b7
- 彻底解决了
问题修复
其他更改
文档
-
Furion单文件发布文档 -
Furion + SqlSugar脚手架文档 - 事件总线文档、选项文档、即时通讯文档、
.NET5升级.NET6文档、依赖注入文档、跨域文档、数据加解密文档
-
本期亮点
- 事件总线
Id支持枚举类型
查看更改
EventSubscribe("TO:DO")] // 字符串类型
public async Task EventHandler1(EventHandlerExecutingContext context)
{
// ....
}
[EventSubscribe(YourEnum.Some)] // 枚举类型
public async Task EventHandler2(EventHandlerExecutingContext context)
{
var eventEnum = context.Source.EventId.ParseToEnum(); // 将事件 Id 转换成枚举对象
// ....
}
- 事件总线发布支持更简单调用
查看更改
// 旧版本
await _eventPublisher.PublishAsync(new ChannelEventSource("ToDo:Create", name));
// 新版本
await _eventPublisher.PublishAsync("ToDo:Create", name);
await _eventPublisher.PublishAsync(YourEnum.Some); // 也支持枚举
- 选项支持属性自定义配置
Key
查看更改
"AppInfo": {
"Name": "Furion",
"Version": "1.0.0",
"Company_Name": "Baiqian" // 可以和属性不一样
}
public class AppInfoOptions : IConfigurableOptions
{
public string Name { get; set; }
public string Version { get; set; }
[MapSettings("Company_Name")] // 支持自定义
public string Company { get; set; }
}
- 日志规范化模板
查看更改
// 生成模板字符串
var template = TP.Wrapper("Furion 框架", "让 .NET 开发更简单,更通用,更流行。",
"[作者] 百小僧",
"[当前版本] v3.5.3",
"[文档地址] https://furion.icu",
"[Copyright] 百小僧, Baiqian Co.,Ltd.");
Console.WriteLine(template);
输出结果
┏━━━━━━━━━━━ Furion 框架 ━━━━━━━━━━━
┣ 让 .NET 开发更简单,更通用,更流行。
┣
┣ 作者: 百小僧
┣ 当前版本: v3.5.3
┣ 文档地址: https://furion.icu
┣ Copyright: 百小僧, Baiqian Co.,Ltd.
┗━━━━━━━━━━━ Furion 框架 ━━━━━━━━━━━
v3.4.2(已发布)
新特性
- 规范化文件
EnableAllGroups功能,可以将多个分组合并到一个分组中 9277b98 -
angular-utils客户端工具库,专门处理angular项目接口代理问题 6c70584 -
Swagger支持单个接口更多描述功能(支持html)e5e1db0 -
Swagger接口[Obsolete]过时支持功能 e5e1db0 - 动态
API的[ApiDescriptionSettings]特性 和DynamicApiControllerSettings配置 的ForceWithRoutePrefix参数,支持强制复写[Route]特性并添加DefaultRoutePrefix#I59B74
- 规范化文件
突破性变化
- 默认内置
GBK,Windows-1252,Shift-JIS,GB2312等编码支持 c456ecb -
Furion和SqlSugar脚手架
- 默认内置
问题修复
-
<inheritdoc />不能跨程序集问题 3b9d39c -
<inheritdoc />不支持带参数,不支持隐式实现接口注释问题 #I59A6W#note_10699021 -
v3.3.1版本导致Swagger不能显示问题 6763352 - 远程请求、
JSON以及Web页面不支持GBK,GB2312等国标编码问题 c456ecb - 远程请求响应报文设置了
Content-Type:charset=不能自动转换编码问题 c456ecb
-
其他更改
-
axios-utils.ts和angular-utils.ts多客户端支持
-
文档
本期亮点
- 启用
All Groups分组功能
查看更改
有时候我们为了更好的对接口进行归类,配置了 Swagger 多个分组的功能,但这样也对生成客户端请求代码造成了困扰,所以添加了新的配置:
{
"SpecificationDocumentSettings": {
"EnableAllGroups": true
}
}
- 接口过时控制
查看更改
当我们某个接口已经过时,提示尽早调用最新接口,只需要在方法上面贴 [Obsolete] 即可,如:
[Obsolete("GetName() 已经过时,请调用 GetFrameworkName() 替代")]
public string GetName()
{
return nameof(Furion);
}
[Obsolete]
public string Other()
{
// ...
}

- 单一接口更多描述
查看更改
在该版本新增了 [ApiDescriptionSettings] 的 Description 属性,支持定义更多描述,如:
[ApiDescriptionSettings(Description = "我是一段描述,显示更多内容 <button>我是按钮</button>")]
public string add()
{
//....
}

v3.3.3(已发布)
新特性
突破性变化
- 代码注释,规范化文档注释
inheritdoc语法支持 ❤️️️️ #159A6W -
.NET所有依赖包至v6.0.5版本
- 代码注释,规范化文档注释
问题修复
- 自定义全局异常
Exception后导致获取错误行号,文件空异常问题 #I53EGM - 配置数据库上下文传递空委托导致空引用异常问题 #I519AW
- 字符串模板模板
Render拓展方法返回void问题,应该返回stringGithub-#99 - 远程请求文件上传出现空情况问题(原因是缺失
Content-Type)I57ZMN
- 自定义全局异常
其他更改
文档
- 粘土对象序列化
JSON配置文档 - 前端解密
JWT文档 - 将
byte[]转url文档 - 二级虚拟目录部署文档,远程请求文档,文件上传文档,安全授权文档、规范化文档
- 粘土对象序列化
本期亮点
- ❤️️️️ 根据文件名获取
MIME或Content-Type类型
- ❤️️️️ 根据文件名获取
查看更改
var success = FS.TryGetContentType("image.png", out var contentType); // image/png
- ❤️️️️ 支持
Swagger配置登录后才能访问
{
"SpecificationDocumentSettings": {
"LoginInfo": {
"Enabled": true,
"CheckUrl": "检查登录地址",
"SubmitUrl": "提交登录地址"
}
}
}

- ❤️️️️ 支持代码注释继承,Swagger 文档注释也支持
查看更改
/// <inheritdoc cref="ITestInheritdoc" />
public class TestInheritdoc : ITestInheritdoc, IDynamicApiController
{
/// <inheritdoc cref="ITestInheritdoc.GetName"/>
public string GetName()
{
return "Furion";
}
/// <inheritdoc />
public string GetVersion()
{
return "3.3.3";
}
}
/// <summary>
/// 测试注释继承
/// </summary>
public interface ITestInheritdoc
{
/// <summary>
/// 获取名称
/// </summary>
/// <returns></returns>
string GetName();
/// <summary>
/// 获取版本
/// </summary>
/// <returns></returns>
string GetVersion();
}

v3.2.0(已发布)
新特性
突破性变化
- 所有依赖包至最新版
- 依赖注入模块核心代码,移除注册服务采用反射机制,减少反射性能损耗 acdb315
问题修复
其他更改
文档
- 定时任务文档,日志文档
- 文件上传/下载 文档,包含单文件/多文件/Base64/Byte[]
v3.1.0(已发布)
新特性
突破性变化
-
.NET6依赖包全部升级至Nuget最新版v6.0.3
-
问题修复
其他更改
- [过时] 标记
Furion.Extras.Logging.Serilog拓展包IWebHost拓展为过时状态
- [过时] 标记
文档
- 优化文档体验,新增面包屑导航,重写文档缓存,提升文档访问速度
- 更新动态 API 文档、配置文档、远程请求文档
- 更新二级虚拟目录文档
本期亮点
- 新增动态
WebApi支持小驼峰路径,如GetMyName->getMyName:
查看更改
{
"DynamicApiControllerSettings": {
"LowercaseRoute": false,
"KeepName": true,
"AsLowerCamelCase": true
}
}
- 支持
.NET6 WebApplication模式二级虚拟目录配置:
查看更改
app.UseVirtualPath(app =>
{
app.UseInject(String.Empty); // 注意 String.Empty 只是例子,可以不填或填其他的,见一分钟入门
app.MapRouteControllers();
});
v3.0.0(已发布)
Furion v3.x 版本采用 .NET6 构建。
新特性
- 远程请求支持
GET请求自动转换类类型类型对象 #I4HR5Q
- 远程请求支持
突破性变化
- 全面支持
.NET6版本
- 全面支持
问题修复
其他更改
-
d0244dToPagedList泛型约束
-
文档
- 查看 .NET6 一分钟入门
- 查看 Furion v2 升级 v3
特别鸣谢
v2.20(已发布,全新事件总线)
在 Furion v2.20+ 版本后采用 Jaina 事件总线替换原有的 EventBus
新特性
- 远程请求支持
GET请求自动转换类类型类型对象 #I4HR5Q
- 远程请求支持
突破性变化
-
EventBus模块,采用 Jaina 方式
-
问题修复
- 开启规范化结果并自定义全局异常导致异常经过
OnSucceeded过滤器 bug #I4DTVL -
.NET5.0.5+微软底层修改了[ApiController]验证失败返回IActionResult类型 #I4ISOK - 远程请求上传文件异常 0c0752
- 框架启动不支持环境变量
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES配置 !438 - 定时任务内存和 CPU 占用及特殊情况下空异常问题 12c65de
- 默认控制器启用规范化结果无效 bugc7a4a5e
- 依赖注入
InjectionAttribute特性的ExceptInterfaces单词拼写错误问题 !436 -
Sql命令参数传入Clay类型异常问题 #I4D21Q
- 开启规范化结果并自定义全局异常导致异常经过
其他更改
文档
- 事件总线新文档
v2.19(已发布)
新特性
问题修复
-
Scoped.Create在EFCore进行Add-Migration时候报空异常问题,原因是在PM环境中不存在根服务0853e74 - 定时任务执行异常后异常一直驻留内存问题,修正为执行成功自动清空过去异常 197a62b
-
Jwt拓展包不正确的代码导致 IOptions 失效#I46LUP -
Swagger枚举Schema过滤器不输出值问题 #I46LON !404 -
Swagger处理非int类型枚举转换 bug #I46QJ9 - 视图引擎编译模板生成
dll后再次加载出现IL格式化错误问题 ff52d38 - 管道
Channel读取器无法释放Handler对象问题 10f4a90 -
Worker Services下日志不输出问题 c482548 - 远程请求
multipart/form-data类型对接微信小程序上传文件 问题 d9bad03 - 工作单元上下文在某些情况下共享事务失效问题 006d439
-
Swagger枚举值在GET请求中Schema显示不正确问题 fb72fd7 - 远程请求
404不走异常过滤器问题 !426 - 自定义事件总线并发情况下调用完成后无法正确处理队列数据 !429
-
v2.19+版本之后模块化开发加载外部程序集失效问题 !433 - 定时任务 SpareTime 频繁检查导致 CPU 增高问题 aa0a2ee
-
特别鸣谢
v2.18(已发布)
新特性
突破性变化
在过去,很多开发者总是喜欢在
Startup.cs配置服务的ConfigureService方法中解析服务,这样导致内存存在溢出风险,GC 无法回收。 正确的方式是尽可能的避免ConfigureService中解析服务。如果需要在【启动时】获取配置选项,请使用App.GetConfig<TOptions>(路径, true)代替App.GetOptions<TOption>。
问题修复
文档
- 包管理工具文档
- 模板引擎、
Sql操作,数据库上下文等等文档
v2.17(已发布)
新特性
突破性变化
问题修复
其他更改
- Swagger 生成泛型 SchemaIds 默认连接符,由
Of改为_81946b6
- Swagger 生成泛型 SchemaIds 默认连接符,由
v2.16(已发布)
新特性
突破性变化
查看更改
using Furion.DataValidation;
using Furion.DependencyInjection;
using Furion.UnifyResult.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Threading.Tasks;
namespace Furion.UnifyResult
{
/// <summary>
/// RESTful 风格返回值
/// </summary>
[SuppressSniffer, UnifyModel(typeof(RESTfulResult<>))]
public class RESTfulResultProvider : IUnifyResultProvider
{
/// <summary>
/// 异常返回值
/// </summary>
/// <param name="context"></param>
/// <param name="metadata"></param>
/// <returns></returns>
public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
{
return new JsonResult(RESTfulResult(metadata.StatusCode, errors: metadata.Errors));
}
/// <summary>
/// 成功返回值
/// </summary>
/// <param name="context"></param>
/// <param name="data"></param>
/// <returns></returns>
public IActionResult OnSucceeded(ActionExecutedContext context, object data)
{
return new JsonResult(RESTfulResult(StatusCodes.Status200OK, true, data));
}
/// <summary>
/// 验证失败返回值
/// </summary>
/// <param name="context"></param>
/// <param name="metadata"></param>
/// <returns></returns>
public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
{
return new JsonResult(RESTfulResult(StatusCodes.Status400BadRequest, errors: metadata.ValidationResult));
}
/// <summary>
/// 特定状态码返回值
/// </summary>
/// <param name="context"></param>
/// <param name="statusCode"></param>
/// <param name="unifyResultSettings"></param>
/// <returns></returns>
public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
{
// 设置响应状态码
UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings);
switch (statusCode)
{
// 处理 401 状态码
case StatusCodes.Status401Unauthorized:
await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "401 Unauthorized")
, App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
break;
// 处理 403 状态码
case StatusCodes.Status403Forbidden:
await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 Forbidden")
, App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
break;
default: break;
}
}
/// <summary>
/// 返回 RESTful 风格结果集
/// </summary>
/// <param name="statusCode"></param>
/// <param name="succeeded"></param>
/// <param name="data"></param>
/// <param name="errors"></param>
/// <returns></returns>
private static RESTfulResult<object> RESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default)
{
return new RESTfulResult<object>
{
StatusCode = statusCode,
Succeeded = succeeded,
Data = data,
Errors = errors,
Extras = UnifyContext.Take(),
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
};
}
}
}
问题修复
-
MVC控制器启用规范化处理后返回new Json({})对象为null问题 #I4354S
-
其他更改
- 多语言底层设计,取消需要创建
Lang.cs空类的要求 #I434YJ -
MiniProfiler性能,减少不必要的监听
- 多语言底层设计,取消需要创建
v2.15(已发布)
新特性
问题修复
其他更改
- 系统启动性能,从 106M 减少到 84M
- 大量底层代码,包大小从 391Kb 减少到 350Kb(不带注释版本仅 64Kb)
v2.13/v2.14(已发布)
新特性
突破性变化
问题修复
其他更改
v2.10/2.11/2.12 (已发布)
该版本有多个破坏性更改,更新时请认真查看。
新特性
-
App.Configuration.Reload()拓展 #I3XYI8 -
ISubscribeHandler支持异步方法定义 #I3XYHJ -
app.UseUnifyResultStatusCodes()可配置修改返回状态码 #I3VZQH - 远程请求添加默认
User-Agent头 #I3W17C - 支持
Sql高级代理切换数据库上下文定位器 #I3XFP6 #I3XDCR - 定时任务
CronFormat自动识别 #I3Y7GT -
Sql 高级代理拦截功能 #I3YHG4 - 拦截远程请求所有异常处理 #I3YPDE
- 远程请求配置
Timeout超时时间 #I3YPPK - 新增
RSA加密算法 #I3YZNU !345 -
DataTable和DataSet支持不指定强类型返回 #I3Z6RI -
Sql字符串拓展方法设置Timeout超时时间 #I3ZKWF -
Sql高级代理[Timeout]特性,设置超时时间 #I3ZKWF
-
突破性变化
-
FakeDelete假删除/软删除所有功能 #I3XKII - 移除
PBKDF2加密算法 #I3Z0IO - 远程请求设置超时时间单位由
分钟改为秒#I3YPPK -
IJsonSerializerProvider接口参数,新增inherit参数 #I3ZQU5 -
[NonAutomatic]特性名称为[Manual]#I3XKKX -
[NotChangedListener]特性名称为[SuppressChangedListener]#I3XKLZ -
[ManualSaveChanges]名称为[ManualCommit]#I3XKNP -
DbContext.TenantIdQueryFilterExpression名称为DbContext.BuildTenantQueryFilter#I3XKTB -
[SkipScan]名称为[SuppressSniffer]#I3XN5N -
[SkipProxy]名称为[SuppressProxy]#I3XN7O -
Sql执行,性能提升 20% #I3W33U
-
问题修复
- 动态 WebAPI 扫描控制器没有屏蔽没有注册的第三方控制器 #I3Y7TJ
-
AppDbContext设置TablePrefix无效: #I3Y57Q - 修复定时任务使用异步委托导致程序终止 bug #I3XVZ0
- 事件总线一个
消息id对应多个Handler只触发第一个#I3XYP0 -
.ToPagedList()分页方法传入小于或等于 0 的页码 #I3XNAN -
JSON序列化默认DateTimeOffset异常 #I3XMOL - 继承
Serilog日志在Worker Service生成重复日志 bug #I3WA0L !331 -
粘土对象动态添加Clay类型 bug #I3W9LW -
ValidationTypes.Numeric校验数值类型正则表达式错误 #I3WADS - 数据库命令参数
DbParameter的Value是object类型的时候且不指定 #I3YKM6 -
Oracle数据库存储过程游标参数报错问题 #I3ZBYE -
Worker Services采用独立发布后无法执行问题 #I3ZH3X - 修复远程请求如果无返回值序列化异常问题 !348
其他更改
文档变化
问答答疑
-
dapper多个数据源如何继承 #I3WUOI - 关于
SpareTime多次执行问题#I3XEQU - 选项更改通知(热更新):数据库里的数据更改了如何通知选项进行改变? #I3XYI8
-
SaaS多租户添加时无法获取租户Id#I3Y5CF - 获取
_httpContextAccessor.HttpContext为空#I3Y6BI -
Ubuntu中使用App.Configuration方法读取不到值 #I3Y74H - 数据库上下文作用域问题 #I3YHXP
- 使用
UnitofWork提交事务,可以提交成功,但是系统会有错误 #I3YIWU - 数据库读写分离--非默认主库的从库随机该如何配置? #I3YVR7
-
v2.9.0 (已发布)
新特性
突破性变化
问题修复
其他更改
- 运行时内存,实现请求结束自动释放未托管资源 #I3VXAU
文档变化
-
App静态类文档、远程请求文档、分表分库文档
-
问答答疑
- 动态 WebAPI,自定义根据方法名生成 [HttpMethod] 规则报错 #I3VKQG
-
InsertAsync的时候提示ID为空 #I3VS7E -
FirstOrDefault自动过滤了TanantId字段 #I3W0VH - 对方接口返回
HttpConnectionResponseContent远程请求拿不到返回值 #I3W17C - 查询方法
FindOrDefault报错 #I3W830 -
SqlNonQuery在UnitOfWork循环执行#I3W8WW - 因
Swagger配置问题,导致Swagger中不能自动携带 token 授权的问题 #I3W934 - 远程请求
SetBody参数识别不了#I3WBM1 -
Scoped.Create里执行sql.SqlNonQuery()或者obj.insert()问题#I3WB5O - 调用函数或存储过程,怎么出参数据自定义对象?如
Oracle数据库的数组或记录 #I3W71W
v2.7.0/2.8.0 (已发布)
新特性
-
throw Oops.On("异常消息")应用多语言支持 #I3UYC2 -
Db.GetMSRepository()获取主从库仓储静态方法 #I3UBSJ - 工作单元特性,支持静态类强制性开启共享事务 #I3S9N8
-
EFCore执行sql模式打印日志 #I3SE8X - 远程请求支持默认
HttpClient配置 #I3SI17 - 新增
短 ID生成功能 #I3T7JP -
[SensitiveDetection]支持配置替换敏感词汇 #I3THIA -
SpecificationDocumentBuilder.DocumentGroups和SpecificationDocumentBuilder.CheckApiDescriptionInCurrentGroup(currentGroup, apiDescription)公开方法#I3UDSY
-
突破性变化
问题修复
-
[DataValidation]和[SensitiveDetection]多语言应用失效 #I3UH6U -
Scoped系列方法异步出现Task is cancel情况 #I3SJF6 -
Mysql数据库的ToPagedList方法返回的结果进行遍历出现MySqlConnection is aleady use问题 #I3SJQ3 -
tool/cli.psl没有包含项目名称 #I3S1T6 - 远程请求做上传文件时,没有传入
Body,程序直接跳过 #I3TKFH - 远程请求
multipart/form-data内容分割符缺失 #I3TNO9 - 远程请求代理拦截方式返回
HttpResponseMessage问题 #I3V161 -
repository.Database.SetCommandTimeout(600)无法生效#I3VAQS
-
其他更改
文档变化
问答答疑
- 默认
MasterDbContextLocator不随自定义的参数生成 #I3SDBB - 事件总线中订阅处理程序类获取不到用户信息,这个正常吗 #I3SS0U
- 在有多租户过滤器的情况下,是否有一种方式查询全量的数据 #I3T0VI
- mysql 使用
&"tools/cli.ps1"页面化加载表结构失败 #I3T4F8 - 其他 Web 层的 Startup 优先执行 #I3T8IP
- 辅助角色服务实现建议 #I3T906
- 开启
easy connection后同一内网地址浏览器可以正常访问,远程请求则无法访问#I3TA2U -
scope.ServiceProvider.GetService<IOtherService>不存在 #I3TQMV - 能否在 WPF 项目中使用呢? #I3TMCC
-
Dapper多个数据源 #I3TM9B -
L.GetSelectCulture()方法异常 #I3TQS4 - 循环中使用
IDGen.NextID()得到的结果并不是连续的 #I3UAF6 - 模块化动态加载插件支持通配符匹配.dll #I3UDT8
-
MVC模式,在Controller里快捷方式创建View页面出错 #I3UFGB - 数据库迁移没有种子数据 #I3UI7G
-
SpareTimeAttribute中 根据 Cron 表达式 自动匹配 Cron 表达式格式化方式 #I3UTKQ - 使用
workService集成SqlSugar报错 #I3V8HJ -
sqlserver 2008分页报错如何解决呢 #I3VF96
- 默认
v2.5.0/2.6.0 (已发布)
新特性
突破性变化
问题修复
- 远程调用方法错误,请求报文头
Headers不能添加到IHttpDispatchProxy的子接口上 #I3RAF7
- 远程调用方法错误,请求报文头
其他更改
- 应用启动性能,减少内存分配
文档变化
问答答疑
- 关于
Furion集群部署 #I3R3J4 - 升级最新框架以后, 数据库生成模型报错 #I3R7TP
- 数据库上下文事务执行中,
SaveNow执行后有警告 #I3RAJI -
Hangfire使用事务出现错误 #I3ROQ5 - 如何实现 cli 不执行某些表的迁移,web 请求可以正常操作呢? #I3ROU5
- 在使用定时任务时候出现的问题:继承
ISpareTimeWorker#I3RRZS -
MySql时间差 8 小时处理 #I3RSCO -
Db.GetRepository<>方法结合[UnitOfWork]后不可用 #I3RUK5 - 事务开启失败问题 #I3RYJY
- 支持
DbProvider可动态配置 #I3RYPE -
WorkService依赖注入ISingleton问题 #I3RZ1L -
ISpareTimeWorker运行期动态修改 #I3S33Q
- 关于
v2.4.0 (已发布)
新特性
突破性变化
- .NET 5 SDK 为 5.0.6 版本
-
IJsonSerializerProvider.GetSerializerOptions()接口方法 #I3QIJN
问题修复
其他更改
-
Furion框架底层性能,减少内存占用,提高应用初始化速度 92f8cc1
-
文档变化
- JSON 序列化文档、规范化结果文档、数据库上下文文档
问答答疑
-
InsertOrUpdateNowAsync报错 #I3QKO5
-
v2.3.0 (已发布)
v2.2.0 (已发布)
新特性
突破性变化
问题修复
其他更改
文档变化
- 粘土对象文档 #I3OG18
问答答疑
v2.1.0 (已发布)
新特性
突破性变化
问题修复
其他更改
- 支持应用启动的时候迁移种子数据 #I3NH3M
文档变化
问答答疑
v2.0.0 (已发布)
新特性
- 控制台应用程序及 Worker Services 支持 #I3K4DG
- 完整任务调度功能 #I3IRUX
-
Cron表达式解析 #I3IQ9Y - 支持
Swagger自定义配置swagger.json地址模板 #I3IHMX - 支持配置动态 WebApi 区域 #I3IJAZ
- 远程请求新增支持传入服务提供器
IServiceProvider#I3IVBL - 全局配置选型
SupportPackageNamePrefixs配置,支持配置包前缀 #I3K0SN - 应用启动时支持
referenceassembly类型程序集扫描 #I3K0SN - 依赖注入
AOP拦截获取方法真实特性 #I3LZBX - EFCore 手动
SaveChanges()特性 #I3N01Y - 支持
Cors跨域更多配置 #I3N2J0
突破性变化
问题修复
- 关闭
InjectMiniProfiler参数后内存缓存无效 #I3IHLR - 在多租户中调用
Tenant属性出现偶然性数据库上下文被释放的情况 #I3IC70 - Sql 代理中如果返回基元类型抛出不能将 object 转换成对应类型的异常 #I3IC84
- 存储过程多返回值的时候,outputvalues 的 name 不是定义的 MSG 的 name,是 Msg 类型。 #I3IC7Y
- PhoneNumber 手机号验证正则表达式错误 #I3ID10
- 依赖注入 AOP 拦截无法捕获内部异常 #I3IGCC
- 全局拦截标记异常已被处理后异常过滤器依然执行 #I3J463
- 自定义全局异常拦截器不起作用 #I3K1SJ
- 在 WorkerService 模式下,还是使用 WebHostEnvironment 来判断 Host 环境,会导致错误 #I3LCQY
- 定时任务
DoOnce抛空异常 bug #I3M0ZT
- 关闭
其他更改
文档变化
问答答疑
- 数据校验,自定义 ErrorMessage 无效问题 #I3ICL3
- 最新 issue 中新增的“新增常用的 JSON 序列化方法” 会导致 AOP 拦截异常 #I3I7VE
- Furion.DatabaseAccessor.PrivateEntityBase 中的 TenantId 数据类型设置为 object #I3IQV6
- 有关异常拦截和处理的疑问 #I3IUFZ
-
DataValidation在空值的情况下被忽略掉了#I3IWSM - 日志文档没有更新 #I3J1DX
- 对于 webapi 简单类型参数,是否可以以 json 方式提交 #I3J18I
-
IUnifyResultProvider实现中如果UnifyModel的 type 不是范型会报错 #I3JBXF - 如何模块化开发新功能? #I3J7ZZ
- 建议增加微服务中间件的集成 #I3JTZQ
- 二级虚拟目录部署的 swagger 的 MiniProfiler js 报错 #I3IWLR
v1.19.0 (已发布)
新特性
突破性变化
- .NET 5 SDK 至 5.0.5 版本
问题修复
其他更改
文档变化
- 数据库上下文、多租户、仓储、日志、序列化等文档。
问答答疑
v1.18.0 (已发布)
新特性
突破性变化
问题修复
其他更改
文档变化
- 数据库操作文档 #I3E84X
问答答疑
v1.17.0 (已发布)
新特性
突破性变化
-
IRepository.AsAsyncEnumerable()返回值 #I3DIQ1,调整为:rep.AsQueryable().ToListAsync()
-
问题修复
其他更改
文档变化
- 远程请求文档 #I3CPJO
问答答疑
v1.16.0 (已发布)
新特性
突破性变化
问题修复
-
MVC模式下不支持验证自定义验证逻辑 #I39LM5 - 验证数值类型正则表达式不支持负数 bug #I39YUV
- 框架启动时无法加载未被引用的程序集 bug #I3A3Z4
-
EFCoreRepository.IsAttached()方法判断错误 bug #I3A824 -
动态API驼峰显示配置无效 bug #I3AF32 -
cli.ps1不支持新版本EFCorebug #I3APO9 -
EFCore实体配置[Table]特性无效 bug #I3BAYH - 动态 WebAPI
CheckIsSplitCamelCasebug #I3BLKX - 修复动态 WebAPI 配置保留 Action 的 Async 后缀无效问题 #I3C3DA
-
JWTToken 刷新后旧的刷新 Token 依旧可用 bug #I3C8ZH - 多语言
Razor视图变量多语言乱码问题 #I3CBMU
-
其他更改
文档变化
问答答疑
-
Furion.Extras.DatabaseAccessor.SqlSugar配置多个数据库打印 SQL 语句问题 #I39PDC -
ORACLE数据库多租户模式下返回值为指定类型时系统卡死 #I39RNH - 假删除指向异常 #I39XZA
-
Furion多语言配置节是放在AppSettings里面还是外面呢? #I3A4SB - 没找到数据库上下文 #I3A5HS
- 有
QQ交流群吗? #I3AAM7 -
Vue3环境下配置SignalR跨域出错 #I3ALQ7 - 设置
Swagger参数非必填 #I3AT02 - EFCore 调用 Insert 时报
Unknown column 'Discriminator' in 'field list'异常 #I3B2LC - 逆向
mysql数据库时cli出现错误 #I3B64F - Sql 高级代理使用过程中 DateTime 类型的参数序列化失败 #I3AZXK
- 使用 Mysql 执行 Add-Migration 报错 #I3B8EW
- Saas 多租户模式-独立 Database 模式下无法获取 Tenant, 导致无法自动切换的问题#I3AVXU
- 如何自定义 WebAPI 统一结果模型 #I3BBYW #I3BBYV
- 在
Web.Entry项目新建了一个Controller,多了未知方法 #I3BKH5 -
AOP拦截如何解析服务 #I3BUM3 - 动态 WebAPI 返回参数被省略 #I3C2XR
- 如何设置某一个接口响应数据不自动转小写,按原始字段名返回 #I38L9B
- code first 如何配置自动迁移 #I3CCR0
- webapi 混合授权如何区分不同系统 #I3CJCY
- EFCore 不支持递归无限级遍历关系 #I3CET9
-
v1.15.0 (已发布)
新特性
突破性变化
问题修复
其他更改
- 代码不规范命名导致开发者阅读代码时产生歧义
文档变化
-
FluentValidation集成文档 #I38IOT
-
问答答疑
-
Furion框架版本向下兼容问题 #I38WMZ
-
v1.14.0(已发布)
新特性
突破性变化
问题修复
其他更改
文档变化
v1.13.0(已发布)
新特性
- 多语言功能及拓展 #I2DOCL
- 事件总线功能及消息中心 #I23BKN
-
Swagger分组显示隐藏配置 #I2AHH8 -
Furion.Extras.Logging.Serilog拓展插件 #I2AAN8 -
cli.ps支持-Namespace命名空间指定 #I2A175 -
Swagger规范化化文档授权失效后自动取消授权锁 #I2AIWC -
Request.Body支持重复读功能,主要解决微信 SDK 问题 #I2AMG0 - 网络请求功能及文档 #I2APGJ
-
SqlSugar拓展包支持打印sql到MiniProfiler中 #I2ASLS -
Furion.Extras.DatabaseAccesssor.Dapper拓展插件 #I2ASYA -
Furion.Extras.DatabaseAccessor.PetaPoco拓展插件 #I2AUGA - 网络请求字符串拓展方法 #I2CPQ0
-
SqlSugar拓展新增PagedList拓展 #I2CW99 - 远程请求支持参数特性验证 #I2CX5L
-
App.User获取当前授权用户信息便捷方法 #I2CZLO - 规范化文档可配置功能,支持
appsettings.json配置 #I2D1K9 - 远程请求拦截器添加方法和方法参数 #I2D2CM
- 远程请求出错返回默认值支持 #I2D44M
- 远程请求
body参数序列化支持设置PropertyNamingPolicy#I2D685 - 远程服务接口客户端配置 #I2D7PS
-
AddInject和UseInject允许自定义SecurityDefinitions和SwaggerUI#I2DIMG -
[SecurityDefine]默认构造函数 #I2DNXT -
AspectDispatchProxy动态代理类 #I2DO6I -
[QueryParameters]特性,支持一键将Action参数添加[FromQuery]特性 #I2G8TF - 动态日志配置及拓展方法 #I2GDGD
-
WebApi请求谓词默认规则配置功能 #I2M70X
突破性变化
-
.NET 5SDK 到.NET 5.0.2版本 #I2D0PZ - 框架内所有拓展类命名空间,全部迁移到
Furion.模块.Extensions下 #I2AH54 -
Swagger记住授权存储方式,替换Session存储方式为LocalStorage方式 #I2AKUA -
Furion框架包描述文件,减少框架体积 #I2APAU -
App.CanBeScanTypes为App.EffectiveTypes#I2B0ZR -
App.ServiceProvider属性并移除App.GetDuplicateXXX方法 #I2CYZE -
Db.GetDuplicateDbContext为Db.GetNewDbContext#I2CZ04 -
Db.GetSqlDispatchProxy为Db.GetSqlProxy#I2DO9T -
Aop服务拦截器,支持异步、同步两种方式 #I2B9HQ - 网络请求所有功能 #I2BMR7
-
问题修复
-
Swagger规范化化结果不一致 bug #I2ACF3 - 数据库新增或更新忽略空值操作方法报空异常 #I2AB6C
-
Startup.csAop 全局拦截无效 #I2A7T2 -
Token过期后自动刷新Token无法获取最新的用户信息 bug #I2AWQI -
[ApiDescriptionSettings(Tag="xx")]导致swagger.json报错 bug #I2B47R -
Mysqlsql 数据库查询结果tinyint类型转换出错 bug #I2BEBM - 规范化结果多次包裹类型 bug #I2BHHZ
- 动态 Api 基元类型数组问题 #I2BMS5
-
sql查询枚举类型转换异常 bug #I2BS2Y -
string.SqlQuerizeAsync<T1>()拓展返回错误 bug #I2BSTS - 动态 Api 子类重写父类方法并取别名后
Swagger异常 bug #I2C9VP - 网络请求
application/json序列化大小写问题 #I2CRJC - 多数据库定位器实体嵌套关联 bug #I2CVN0
- 跨域响应头设置无效 bug #I2CW5T
- 远程网络请求代理打印到
MiniProfilerbug #I2CZBC - 远程请求响应拦截器 bug #I2D4DG
-
SqlSugar框架AsQueryable()一直追加参数 #I2DH1D - 自动刷新
Token空异常 bug #I2DO29 - 生成
JWT Token不传过期时间出现验证 401 bug #I2DO8L -
AppStartup排序无效 #I2DVD2 - 未启用多语言服务时友好异常和验证出现空异常 #I2ECUJ
- 数据校验字母和数字组合无法匹配 bug #I2EF2Q
- 数据校验手机或固话无效 bug #I2M5IZ
-
Dapper拓展解析SqlConnection异常 bug #I2M5P2 - 开启多语言后,
EF迁移异常 bug #I2M7DT -
IEntityTypeBuilder不支持多重继承 bug #I2PAOD -
JwtHandler设置自动刷新后,匿名访问无法通过 bug #I2SDOX -
Dapper拓展中SqlServer数据库获取连接对象类型 bug #PR159
-
其他更改
文档变化
问答答疑
- 跨域设置无效 #I2ASNJ
-
MVC视图无效,原因是.cshtml文件没有设置为内容#I2AXUU -
Sql操作可以实现事务吗?#I2B0NX -
IRepository操作数据库会打开多次数据库连接 #I2BB7B - 如何进入自定义
AppAuthorizeHandler断点 #I2BGXY -
SqlSugar注入问题 #I2C2AQ - 建议增加 API 签名验证,时效验证 #I2C6ET
- 多数据库多租户同时使用
Add-Migration报错 #I2CEHS -
ISqlSugarRepository没有Getxxx方法 #I2CJLZ -
cli.ps1如何将sql里的表导出成model类 #I2CSUL - 手动修改
Swagger终结点路径无效 #I2D608 -
DefaultDbContext不能识别 #I2DCZX - 各分层项目
Startup.cs支持Configuration#I2DDUP -
Aop无法拦截,无效 #I2DEY8 -
mysql执行Add-Migration报错 #I2DSB8\ -
Entity创建时间和是否删除添加默认值 #I2E04H -
swagger中多个servers设置 #I2E0IF - 全局筛选器 没有执行 #I2E5R4
- 多数据库定位器疑问 #I2E77T
-
cli.ps逆向工程Mysql数据库报错 #I2E7I5 -
Swagger开发环境applicationsettings.json中文乱码 #I2EAG1 - 增加指定路径程序集映射 #I2EEO2
- 动态编译
cs脚本文件 #I2EH66 - 自定义中间件,返回的错误没有规范化结果 #I2NV8S
-
Swagger循环引用设置生成文档层级无效 #I2PLQQ - 配置文件支持
yaml文件吗? #I2TJ3N - 修改数据库未
mysql执行Add-Migration报错 #I2VR64 - 多数据库使用定位器时报错 #I2VR8F
-
Migration To Oracle异常 #I2WBYQ - 开发时显示
Swagger,上线时关闭Swagger,这需要怎么配置 #I2WOYV - 兼容 Mvc 复杂验证没有试验成功 #I2X3GV
-
Aop能不能支持无接口的类 #I2X8AS - 关于
JWT Token自动刷新问题 #I2YD4K - 能否增加一个拓展的
Entity,增加一些拓展的属性 #I2YDKT -
Furion无法还原包,使用Nuget下载和通过最新的的脚手架下载都提示这个问题 #I30446 - 复杂校验与特性验证不能并行 #I3046U
v1.7.0(已发布)
新特性
-
Furion.Extras.ObjectMapper.Mapster拓展包 #I29LSJ -
Furion.Extras.Logging.Serilog拓展包 #I2AAN8 -
Furion.Extras.Web.HttpContext拓展包 #I29LSM - 内置
Token刷新机制支持 #I29K57 - 动态数据库上下文,支持运行时执行
OnModelCreating#I28UDT - 支持依赖注入排除指定接口 #I29693
- 规范化结果返回时间戳字段 #I29697
- 基础
CURD父类操作例子 #I296SR -
sql.Change("定位器完整类型名称")支持 #I29LAB -
UpdateInclude和UpdateExclude忽略空参数支持 #I29VUG - 数据库上下文内置假删除查询过滤器支持 #I29Y2R
- 忽略空值排除默认时间格式 #I29VUV
-
MiniProfiler组件 #I297R9
-
突破性变化
-
AppAuthorizeHandler授权管道为异步处理 #I29MD9 -
Swagger默认启用JWT授权支持 #I29LI4 -
HttpContextUtilities名称改为HttpContextLocal#I29KQE -
UnifyResultContext名称改为UnifyContext#I29LLZ - 只有执行迁移命令才扫描种子数据 #I29E6P
- 规范化结果
Successed属性名为Succeeded#I29NMV -
Mapster对象组件,采用提供拓展方式 #I29D2M -
CacheManager拓展类 #I29LU1 -
SaveChanges拦截器 #I292LO
-
问题修复
- 未注册的数据库上下文也被引用全局查询拦截器 bug #I29ZXJ
- 手动返回
BadObjectResult或ValidationProblemDetails结果类型时规范化结果失效 bug #I29ZU9 - 动态 WebApi
KeepName,KeepVerb、SplitCamelCase无效 bug #I29X90 -
Sql代理返回元组类型出错 bug #I29SMV -
401,403状态码规范化返回值属性变大写 bug #I29M8Y -
HttpContext空异常 bug #I29LU4 - 接口无返回值没有应用规范化结果 bug #I29GT7
- 前端
Less配置文件导致主机启动失败 bug #I29E7P - 执行
sql结果转泛型后属性重复赋值 bug #I29BUO -
Swagger关闭MiniProfiler之后组中组失效 #I29789 - 未启用规范化结果时异常返回
System.Object字符 #I2969A - 正数数据验证 0 也验证通过 bug #I2955T
- 非泛型类集成泛型接口依赖注入 bug #I294YT
-
Swagger不支持new覆盖父类的 bug #I28Z1A -
JsonSerializerUtility没有公开 bug #I28WMI -
SqlSugar拓展查询泛型类型注册异常 bug #I28VMT -
Furion Tools不支持生成不同命名空间的实体 bug #I2A175 - 全局拦截器无效 bug #I2A7T2
- 新增或更新忽略空值空异常 bug #I2AB6C
其他更改
-
Token生成加密算法 #I29KIH
-
文档变化
- 日志文档 #I28Y9D
- 数据库上下文、实体拦截器、配置、一分钟入门等等文档
问答答疑
v1.4.0(已发布)
新特性
-
Furion支持二级虚拟目录部署功能 #I28B77 -
Furion.Template.RazorWithWebApi脚手架 #I28QGI -
Furion.Template.BlazorWithWebApi脚手架 #I27Z3O -
EFCore时态查询拓展 #I28AJ -
[AppDbContext(连接字符串,数据库类型)]配置支持 #I28QTB -
DateTimeOffset转DateTime拓展方法 #I27MQA -
ValidationTypes验证正则表达式智能提示 #I2801V -
ValiationTypes.WordWithNumber验证 #I2805 - 获取客户端和服务端 IP 地址 #I28QV9
-
突破性变化
问题修复
- 多数据库上下文配置定位器后实体无法正确生成 bug #I2888L
- 多租户数据库上下文实体生成 bug #I2891G
- 对象验证失败提示消息没有应用
JSON大小写配置 bug #I27UTX - 仓储
Insert或Update方法指定ignoreNullValues无效 bug #I27UN6 -
Controller派生类如果贴了[Route]特性后出现在Swagger中 bug #I27TN7 -
SqlScalar执行sql返回Nullable类型出现转换失败 bug #I27S2N -
[UnitOfWork]特性异常 bug #I27MLM -
sql静态执行方式和sql高级代理无法监听数据库连接状态 bug #I27M4F - 修复更换 Json 序列化库无效 bug,如替换为
Microsoft.AspNetCore.Mvc.NewtonsoftJson#I27M43 -
Furion Tools工具生成模型 bug #I27XI5 - 软删除没有生效 bug #I2804I
-
Furion Tools识别带多个\\的连接字符串识别 bug #I280TS,#PR91 -
Furion Tools无法取消生成 bug #I2816M -
DateTimeOffset转本地时间差 8 小时 bug #I28BA9 - 启用
bundle js&css压缩后启动异常 bug #I28KR -
ValidationTypes.Required无效 bug #PR98 - 规范化结果
OnValidateFailed参数名拼写错误 bug #PR93,#PR92 - 授权管道验证失败还显示结果 bug #PR89
其他更改
文档变化
问答答疑
v1.2.0(已发布)
新特性
- 雪花算法 #I26OXG, #PR78
-
[AppDbContext]配置数据库提供器支持 #I27G3T - 实体表数据更改监听接口
IEntityDataChangedListener#I278DD, #I278LQ - 全局服务接口 AOP 拦截功能 #I278CP
- 定位器仓储
IDbRepository<TDbContextLocator>#I276Q3 - 数据库操作
InsertOrUpdate支持排除空字符串功能 #I272OG - 数据库操作
UpdateInclude和UpdateExclude匿名对象支持 #I271X0 - 数据验证传入空对象跳过验证支持 #I273R4
- 应用启动时支持排除特定配置文件自动加载 #I26U0A
- 单个实体表名前缀支持 #I26LX0
-
MySql数据库自动配置默认版本号 #I26XQ6 - 授权处理程序代码
突破性变化
问题修复
- 视图引擎加载外部程序集出错 bug
- 依赖注入代理接口报空对象异常 bug
-
EFCore取消附加实体出错 bug - 数据库仓储在非 Web 请求下出现空异常 bug
- 多个授权策略共存问题出现无效 bug
- 友好异常
Oop.Oh不支持普通方法 bug - 获取多租户对象时数据库上下文出现作用域验证失败 bug
- 工作单元不支持
Sql代理拦截 bug #I27GST
文档变化
- 实体数据监听器 文档
- 一分钟入门、应用启动、官方脚手架、数据库操作指南、对象映射、规范化文档、异常处理、鉴权授权文档
v1.1.0(已发布)
新特性
-
Db.GetDbContext()获取默认数据库上下文方法 -
HttpContextUtility.GetCurrentHttpContext()获取全局HttpContext上下文 -
App.GetRequiredService<>解析服务方法 -
object.GetService<>对象拓展方法 - 策略授权
PolicyPipeline基类方法,支持多重判断授权 -
JWTEncryption.ValidateJwtBearerToken手动验证静态方法 - 全局数据库上下文
InsertOrUpdateIgnoreNullValues和EnabledEntityStateTracked全局配置 -
Swagger Jwt授权全局授权参数 #I26GLR -
InsertOrUpdate支持自定义判断条件功能 #I269Q1 - 字符串字段小写命名支持 #I2695D
- 字符串文本对比功能 #I268LE
- 全局异常特性消息功能 #I2662O
-
Insert或Update数据库忽略空值功能 #I264Q4
-
突破性变化
-
Fur项目名为Furion -
Db.GetRequestDbContext<>()命名为Db.GetDbContext<>() -
Db.GetDbContext<>()命名为Db.GetDuplicateDbContext<>() -
App.GetService<>解析服务的底层逻辑,大大提高了解析服务的性能 - 授权核心代码,保持和微软一致的授权规范 #I26DCB
-
App.GetRequestService<>方法 -
ValidateJwtBearerJwt 授权方法,无需手动判断了
-
问题修复
- Furion 官方脚手架生成后编译异常 bug
-
Tenant内置属性不是virtual修饰 bug -
dockerfile新命名构建失败 bug - 自定义角色授权和多个授权共存出现 403 bug #I26H1L
-
httpContext.GetEndpoint()空异常 bug #PR73 -
Oops.Oh空异常和不支持服务抛异常 bug #I26EFU,#I26GM4 -
cli.ps生成文件编码乱码 bug #I26DVT -
Swagger文件上传按钮不显示 #I26B6U - 规范化结果授权状态码序列化大小写不一致问题 #I26B26
- 未启用规范化结果时中文乱码 bug #I268T5
-
MySql异步异常捕获不到 bug #I265SO -
cli.ps1提示找不到数据库连接字符串 bug #I2647U
其他更改
- 代码性能小优化和小调整
文档变化
- 一分钟入门、安全鉴权、数据库等文档
v1.0.3(已发布)
新特性
- Mvc 模板脚手架:
Fur.Template.Mvc - WebApi 模板:
Fur.Template.Api - Mvc/WebApi 模板:
Fur.Template.App - Razar Pages 模板:
Fur.Template.Razor - Blazor 模板:
Fur.Template.Blazor
- Mvc 模板脚手架:
突破性变化
-
PagedList到System.Collections.Generic命名空间下 - 解析服务性能问题,底层代码大量优化
-
问题修复
文档变化
- 入门文档、数据库上下文文档、多数据库操作文档
v1.0.2(已发布)
新特性
突破性变化
-
Mapster包至7.0.0版 -
App.Services名为App.ServiceProvider -
App.ApplicationServices和App.GetRequestService<>() - 非 Web 主机注入拓展
-
问题修复
其他更改
-
EntityBase和Entity所有属性为vitural修饰 -
Jwt读取和解析性能 - 优化代码支持 C# 9.0 最新语法
-
MD5加密性能 #PR71 - 无用或未使用代码
-
文档
- 数据库上下文、多数据库、一分钟入门文档
v1.0.0(已发布)
新特性
- 网络请求
RemoteRequest组件 #I1YYWD -
.AddInjectBase()注入,只包含基础服务注入 - 所有服务都支持
IServiceCollection和IMvcBuilder注入 - 抛异常状态码设置功能
StatusCode -
Swagger序列化支持Pascal属性命名方式
- 网络请求
突破性变化
- 所有的包为
.NET 5正式版
- 所有的包为
问题修复
-
SqlProxy代理异步处理 bug - 数据库类型
Datetime转DateTimeOffsetbug - 属性首字母大小写序列化不匹配出现
nullbug - 对象序列化中文出现乱码 bug
- 默认序列化配置无效 bug
- 数据库非依赖注入方式提交无效 bug
- 应用程序池提交所有
DbContext空异常 bug -
Saas多租户Tenant类型字符串属性在MySql数据库下出现longtext类型 bug -
Mvc自动验证字符串空值 bug #I24M2T - 枚举注释被覆盖 bug #I24N6J
- 忽略规范化结果无效 bug #I24B8P
-
Swagger默认ContentType不是applicaiton/jsonbug #I24F3U - 内置
System.Text.Json和Newtonsoft.Json冲突 bug #I24F3U
-
其他更改
-
Fur框架域名为:https://furion.icu - 仓储
FromSqlRaw和FromSqlInterpolated接口位置 - 数据加解密性能,#PR70
-
文档
- README.md、框架介绍、数据库上下文、配置选项、多租户、跨域文档
